What is idiomatic C # for unpacking an integer from a byte array?

I am parsing a binary file format. It encodes an integer using four bytes in a way that will naturally conform to a C # uint type.

What is the most C # / idiomatic way to implement this feature:

uint ReadUint(byte[] buffer);

      

Suppose the buffer contains 4 elements. The complete answer can look at some of the common byte orders caused by small / large arguments in the file and document the ones it chooses to parse.

+1


a source to share


7 replies


The simplest (but a bit dangerous re endianness):

return BitConverter.ToUInt32(buffer, 0);

      

Also, bit shift is ok (as per your own answer) - or you can use Jon EndianBitConverter in MiscUtil which handles translations.



(edit)

The little bit shift version I use in protobuf-net is very similar to your version - I just read them in ascending order and use bitwise (not numeric) complement:

return ((uint)buffer[0])
        | (((uint)buffer[1]) << 8)
        | (((uint)buffer[2]) << 16)
        | (((uint)buffer[3]) << 24);

      

+5


a source


I would normally use the BitConverter class for this. In your case, the BitConverter.ToUInt32 () method .



+2


a source


This answer is actually an extended comment (hence the wiki) comparing BitConverter and bitrate performance using + vs |; it only applies to micro-optimization !!

Results first:

BitConverter: 972ms, chk=1855032704
Bitwise: 740ms, chk=1855032704
ReadLength: 1316ms, chk=1855032704

      

Or the results, if configured to allow non-zero base offsets:

BitConverter: 905ms, chk=1855032704
Bitwise: 1058ms, chk=1855032704
ReadLength: 1244ms, chk=1855032704

      

And the code:

using System;
using System.Diagnostics;
static class Program
{
    static void Main()
    {
        byte[] buffer = BitConverter.GetBytes((uint)123);
        const int LOOP = 50000000;
        uint chk = 0;
        var watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += BitConverter.ToUInt32(buffer, 0);
        }
        watch.Stop();
        Console.WriteLine("BitConverter: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += Bitwise(buffer);
        }
        watch.Stop();
        Console.WriteLine("Bitwise: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        chk = 0;
        watch = Stopwatch.StartNew();
        for (int i = 0; i < LOOP; i++)
        {
            chk += ReadLength(buffer);
        }
        watch.Stop();
        Console.WriteLine("ReadLength: " + watch.ElapsedMilliseconds
            + "ms, chk=" + chk);

        Console.ReadKey();
    }
    static uint Bitwise(byte[] buffer)
    {
        return ((uint)buffer[0])
            | (((uint)buffer[1]) << 8)
            | (((uint)buffer[2]) << 16)
            | (((uint)buffer[3]) << 24);
    }
    static uint ReadLength(byte[] buffer)
    {
        uint result = ((uint)buffer[3]) << 24;
        result += ((uint)buffer[2]) << 16;
        result += ((uint)buffer[1]) << 8;
        result += buffer[0];
        return result;
    }
}

      

+2


a source


As someone from C, this is how I implement this function:

static uint ReadLength(byte[] buffer)
{
    uint result = ((uint) buffer[3]) << 24;
    result |= ((uint) buffer[2]) << 16;
    result |= ((uint) buffer[1]) << 8;
    result |= buffer[offset];
    return result;
}

      

This parses the Wikipedia asserted format, in little-endian style, in the .NET version running on i386 / Vista p>

+1


a source


Assuming you want to read a stream of them (as your code suggests) I would say this is pretty close to the actual standard:

MemoryStream ms = new MemoryStream(new byte[100]);
BinaryReader br = new BinaryReader(ms);
uint q = br.ReadUInt32();

      

0


a source


byte[] ba = new byte[]{ 0x10, 0xFF, 0x11, 0x01 } ;
var ui = BitConverter.ToUInt32(ba, 0);

      

Use the BitConverter class .

0


a source


The easiest way is just

int val  = System.BitConverter.ToInt32(buffer, 0);

      

This uses the current system entity, which may or may not be what you want.

0


a source







All Articles