Yet another developer journey ...

Yet another developer journey ...

Converting hex/bytes/int drama got a happy end

Converting hex/bytes/int drama got a happy end

Dominik Schischma's photo
Dominik Schischma
·Jun 2, 2022·

3 min read

You won't believe how happy I have been, when I noticed the new BitConverter class in .Net. Finally, stop taking some stupid helper class around with you, just for converting byte to hex or other types and vice versa for example for debug logging. Now mostly a simple one-liner!

We take a very short look into BitConverter

byte to hex dump

BitConverter.ToString

// 104 is the int representation of the char 'h', hex '68'
// 105 is the int representation of the char 'i', hex '69'
byte[] someByteArr = new byte[2] {104,105}; 

string hexDump = BitConverter.ToString(someByteArr);
Console.WriteLine(hexDump);
// output: 68-69

There are numerous hexadecimal notations. For example: 68-69, 0x68 0x69, \x68 \x69 and so on... If Hexadecimal is unknown to you, I strongly recommend reading the article from Wikipedia as it will improve your understanding massively.

bytes to int32 (exemplary)

Simply:

byte[] someByteArr = new byte[2] {132,1};

short result = BitConverter.ToInt16(someByteArr);
Console.WriteLine(result);
// output: 388

When converting this way, please remind the byte required byte array length (e.g., 2 bytes for int16/4bytes for int32/8bytes for int64) and the order of bytes you received (host byte order or network byte order / lowHIGH or HIGHlow).

Some little history: In general, it is called 'endianness', the order of the bytes of a word in the memory, where we have big-endian and little-endian. In the beginning the mainframes dominated the world which all used big-endianness. When the personal computer came up it switched to little-endianness. However, the network is still mostly big-endianness because the IETF RFCs (public declarations of protocols) use them. You can read more about this at Wikipedia. You can test endianness yourself if you simply switch the bytes in the upper array:

byte[] someByteArr = new byte[2] {1,132};

short result = BitConverter.ToInt16(someByteArr);
Console.WriteLine(result);
// output: -31743

The framework itself does implement IPAddress.HostToNetworkOrder and IPAddress.NetworkToHostOrder for switching between the endiannesses. As an alternative, just use Array.Reverse.

Converting one byte to int representation

The conversion is still using the good old Convert class. Where we simply can convert one byte to the corresponding representation. This is a hard conversion, so exceptions may and often happen. We are just converting the representation, not dealing with the real 'data'. For example, a byte can be also expressed using an int as used in above examples for the byte array initialization:

byte[] someByteArr = new byte[2] {132,1};

int result = Convert.ToInt32(someByteArr[0]);
Console.WriteLine(result);
// output: 132

result = Convert.ToInt32(someByteArr[1]);
Console.WriteLine(result);
// output: 1

Just taking an exit before the end to go the way through unsigned/signed

Here we will use integer / int here. uint stands for unsigned integer whereas int is for signed integer. Unsigned integers can only have positive values and signed also negative. In the memory itself however, the occupied space is the same so a 'trick' is used to accomplish this resulting in different ranges: int -2,147,483,648 to 2,147,483,647 uint 0 to 4,294,967,295 You can read more about this here.

As the data in the memory is different, the type is important for casting. If the wrong type is used an 'overflow' may happen which does result in wrong interpretation of the data.

I will not dive deep into the memory storage itself, there are much better articles about that for example at Wikipedia, which you already find referenced in this article.

Credits

Photo by mostafa meraji on Unsplash

 
Share this