10

I am trying to read a binary file in C#, but I am facing a problem. I declared the following:

public static readonly UInt32 NUMBER = 0XCAFEBABE;

Then while reading from the very beginning of the file I am asking to read the first 4 bytes (already tried different ways, but this is the simplest):

UInt32 num = in_.ReadUInt32(); // in_ is a BinaryReader

While I have that the 4 bytes are CA, FE, BA and BE (in hex) while convert them to UInt I am getting different values. NUMBER is 3405691582, num is 3199925962. I also tried to do this:

byte[] f2 = {0xCA, 0xFE, 0xBA, 0xBE};

and the result of doing BitConverter.ToUInt32(new byte[]{0xCA, 0xFE, 0xBA, 0xBE},0) is 3199925962.

can anyone help me?

Roberto Caboni
  • 7,252
  • 10
  • 25
  • 39
pinker
  • 1,283
  • 2
  • 15
  • 32

2 Answers2

9

This is because of the little endianness of your machine. See BitConverter.IsLittleEndian property to check this.

Basically, numbers are stored in reverse byte order, compared to how you would write them down. We write the most significant number on the left, but the (little endian) PC stores the least significant byte on the left. Thus, the result you're getting is really 0xBEBAFECA (3199925962 decimal) and not what you expected.

You can convert using bit shifting operations:

uint value = (f2[0] << 24) | (f2[1] << 16) | (f2[2] << 8) | f2[3];

There are many more ways to convert, including IPAddress.NetworkToHostOrder as I4V pointed out, f2.Reverse(), etc.

For your specific code, I believe this would be most practical:

uint num = (uint)IPAddress.NetworkToHostOrder(in_.ReadInt32());

This may result in an arithmetic underflow however, so it may cause problems with a /checked compiler option or checked keyword (neither are very common).

If you want to deal with these situations and get even cleaner code, wrap it in an extension method:

public static uint ReadUInt32NetworkOrder(this BinaryReader reader)
{
    unchecked
    {
        return (uint)IPAddress.NetworkToHostOrder(reader.ReadInt32());    
    }
}
Thorarin
  • 47,289
  • 11
  • 75
  • 111
  • `IPAddress.NetworkToHostOrder` – I4V Apr 19 '13 at 10:55
  • @I4V I keep forgetting about that method. Whoever put that in the `IPAddress` class... Unfortunately there is no UInt32 version of the method, so that will require some extra fiddling. – Thorarin Apr 19 '13 at 10:58
  • `IPAddress.NetworkToHostOrder` converts between the endianness of IP Addresses in the IP protocol packets (big-endian) and host order (little-endian on x86, but could be big-endian on other architectures like ARM). Don't get into the habit of using this function to reverse endianness, because it will not work cross-platform. – smead Dec 17 '16 at 02:33
4

That's what is called byte order:

var result1 = BitConverter.ToUInt32(new byte[] { 0xCA, 0xFE, 0xBA, 0xBE }, 0);
//3199925962

var result2 = BitConverter.ToUInt32(new byte[] { 0xBE, 0xBA, 0xFE, 0xCA }, 0);
//3405691582
Hossein Narimani Rad
  • 31,361
  • 18
  • 86
  • 116