19

Im trying to cast a 4 byte array to an ulong in C#. I'm currently using this code:

atomSize = BitConverter.ToUInt32(buffer, 0);

The byte[4] contains this:

0 0 0 32

However, the bytes are Big-Endian. Is there a simple way to convert this Big-Endian ulong to a Little-Endian ulong?

Community
  • 1
  • 1
WesleyE
  • 1,384
  • 1
  • 12
  • 29

7 Answers7

24

I believe that the EndianBitConverter in Jon Skeet's MiscUtil library (nuget link) can do what you want.

You could also swap the bits using bit shift operations:

uint swapEndianness(uint x)
{
    return ((x & 0x000000ff) << 24) +  // First byte
           ((x & 0x0000ff00) << 8) +   // Second byte
           ((x & 0x00ff0000) >> 8) +   // Third byte
           ((x & 0xff000000) >> 24);   // Fourth byte
}

Usage:

atomSize = BitConverter.ToUInt32(buffer, 0);
atomSize = swapEndianness(atomSize);
Yves M.
  • 29,855
  • 23
  • 108
  • 144
Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
  • 1
    Thanks, maybe you could show me what you are doing per line? That would be awesome, I've never used bit shifting until now. – WesleyE Jul 20 '10 at 22:09
  • 1
    @WesleyE: I've rewritten it to make it a little clearer. It handles one byte at a time, masks out the 8 bits and then shifts then into their new position. The four bytes are then added together to give the result. If you don't understand what bitshifting is, I recommend this question + answer: http://stackoverflow.com/questions/141525/absolute-beginners-guide-to-bit-shifting – Mark Byers Jul 20 '10 at 22:14
  • 1
    It is faster to remove the and-operations and cast to byte each time. – usr Jun 14 '12 at 21:00
  • You can install MiscUtil via Nuget: https://www.nuget.org/packages/JonSkeet.MiscUtil/ – Yves M. Dec 18 '14 at 12:20
10

In .net core (>= 2.1), you can use this instead:

BinaryPrimitives.ReadUInt32BigEndian(buffer);

That way, you're sure of the endianness you're reading from.

Documentation

It's implemented there in case you're wondering how it works

Edit: as mentionned by @smkanadl in the comments, it seems that you can use this API as well in .net framework by installing the System.Memory package.

cube45
  • 3,429
  • 2
  • 24
  • 35
  • Best solution, because it doesn't require bit fiddling or additional iterations of the buffer (`Array.Reverse()`) or additional allocations (`buffer.Reverse().ToArray()`). – Good Night Nerd Pride Dec 24 '21 at 21:48
  • This solution is not limited to .net core. You can simply install the `System.Memory` nuget package. – smkanadl Aug 04 '22 at 16:38
7

System.Net.IPAddress.NetworkToHostOrder(atomSize); will flip your bytes.

Mark H
  • 13,797
  • 4
  • 31
  • 45
  • 3
    Not necessarily. If your host is already big-endian, no change will be made. – Jeff Mercado Aug 18 '12 at 18:30
  • Doesn't matter, Jeff.The point is,if the system is already big endian, then BitConverter would have read it as BigEndian and no change would be needed anyway.Unfortunately, using this function or Jon's convert can have some serious performance penalties, if say you are working with a file that contains hundreds of thousands of them.If this is the case then you should go with Mark Byers suggestion.The only way to get faster is to make CPU specific functions i.e. x86 has the BSWAP assembly instruction which is much faster than bit shifting. This function is perfectly fine for packet processing – Rahly Nov 30 '15 at 16:50
5

I recommend using Mono's DataConvert which is like BitConverter on steroids. It allows you to read in big-endian byte arrays directly and improves massively on BitConverter.

A direct link to the source is here.

Callum Rogers
  • 15,630
  • 17
  • 67
  • 90
4
BitConverter.ToUInt32(buffer.Reverse().ToArray(), 0)

No?

Nick Daniels
  • 922
  • 8
  • 13
2

This may be old but I'm surprised no one came up with this simplest answer yet, only requires one line...

// buffer is 00 00 00 32
Array.Reverse(buffer);
// buffer is 32 00 00 00
atomSize = BitConverter.ToUInt32(buffer, 0);

I'm using it to compare checksums generated in C# (little-endian) with checksums generated in Java (big-endian).

IaguCool
  • 43
  • 1
  • 4
  • Not the same thing. if buffer is 00 00 00 32 54, then your buffer is after the reverse is 54 32 00 00 00, so a ToUInt32 will not give you the value 32. If your buffer is always length 4 then this will work just fine. To make it work it work for different lengths, you would need Length-4 instead of 0 after the Reverse. – Rahly Nov 30 '15 at 16:59
  • 2
    The topic is "C# Big-endian ulong from 4 bytes", and this was my answer specific to the question, I never said this was a solution for every case, but for defined numeric data types (16-bit, 32-bit, 64-bit, etc) it's sufficient as long as the target byte-array has the same number of bytes. – IaguCool Nov 30 '15 at 20:30
0
firstSingle = BitConverter.ToSingle(buffer,0);
secondSingle = BitConverter.ToSingle(buffer,2); 

var result = BitConverter.ToUInt32(BitConverter.GetBytes(secondSingle).Concat(BitConverter.GetBytes(firstSingle).ToArray());
Tormod
  • 4,551
  • 2
  • 28
  • 50