Search code examples
c#bytedata-conversion

Converting correctly Byte array to long C#


I would like to convert a byte array (byte[]) to a long in C#. I have already been able to research this and this thread is NOT a duplicate. Indeed, I need the conversion to be BigEndian which is done this way in Java:

ByteBuffer buf = ByteBuffer.wrap(digest);
Long bufLong = buf.getLong(12); // int parameter = start index;

For exemple, here is a Java / C# convertion comparaison. Java:

public static void testLong()
    {
        byte[] testLong = new byte[]{
                (byte) 0xac, (byte) 0xe0, (byte) 0x46, (byte) 0x0b, (byte) 0xff,
                (byte) 0x30, (byte) 0xbf, (byte) 0xbf, (byte) 0x86, (byte) 0xc3,
                (byte) 0xaf, (byte) 0xf4, (byte) 0x6b, (byte) 0xfe, (byte) 0xc2,
        };

        ByteBuffer byteBuffer = ByteBuffer.wrap(testLong);

        for (int i = 0; i < (testLong.length - 8); i++) {
            System.out.println("i[" + i + "]: " + byteBuffer.getLong(i));
        }
    }

C#:

 public static void TestLong()
        {
            byte[] testLong = new byte[]{
                    (byte) 0xac, (byte) 0xe0, (byte) 0x46, (byte) 0x0b, (byte) 0xff,
                    (byte) 0x30, (byte) 0xbf, (byte) 0xbf, (byte) 0x86, (byte) 0xc3,
                    (byte) 0xaf, (byte) 0xf4, (byte) 0x6b, (byte) 0xfe, (byte) 0xc2,
            };

            for (int i = 0; i < (testLong.Length - 8); i++)
            {
                Console.WriteLine($"I[{i}] : {BitConverter.ToInt64(testLong, i)}");
            }

            Array.Reverse(testLong);
            Console.WriteLine("Reversing the array ...");

            for (int i = 0; i < (testLong.Length - 8); i++)
            {
                Console.WriteLine($"I[{i}] : {BitConverter.ToInt64(testLong, i)}");
            }
        }

Java Output (Correct one):

i[0]: -5989710487062790209
i[1]: -2286126570181509242
i[2]: 5047408392239285955
i[3]: 864463253588591535
i[4]: -58335965835186188
i[5]: 3512736819901887595
i[6]: -4629833716884804610

C# Output (Incorrect):

I[0] : -4629928019949592404
I[1] : -8737054534917208352
I[2] : -4357584761552696506
I[3] : -5781629338509050101
I[4] : -815218024020758273
I[5] : 7779035710689886000
I[6] : -113728329830973505

Reversing the array ...

I[0] : -4645810805098676542
I[1] : -4629833716884804610
I[2] : 3512736819901887595
I[3] : -58335965835186188
I[4] : 864463253588591535
I[5] : 5047408392239285955
I[6] : -2286126570181509242

Note that i test to reverse the array because Java is BigEndian and C# is LittleEndian (Probably also the source of my problem but idk)

As you can see the convertion is not good.

I also tried to use a ByteBuffer port in C# without sucess: https://github.com/google/flatbuffers/blob/master/net/FlatBuffers/ByteBuffer.cs

If someone can help me with this problem, i would really appreciate it.


Solution

  • C# is not any endian - in that unless you cheat and look under the covers: endianness is not a factor you see; .NET in general, and BitConverter in particular, are CPU-endian; and presumably your CPU is little-endian.

    So: don't use that! BinaryPrimitives offers explicit-endian APIs; use the ones that are correct for your scenario.

    Note: when reversing data for endianness reasons, you'd only reverse that segment, not the entire payload - which is why your Reverse attempt failed.

    using System;
    using System.Buffers.Binary;
    
    ReadOnlySpan<byte> testLong = new byte[]{
        0xac, 0xe0, 0x46, 0x0b, 0xff,
        0x30, 0xbf, 0xbf, 0x86, 0xc3,
        0xaf, 0xf4, 0x6b, 0xfe, 0xc2,
    };
    
    for (int i = 0; i < (testLong.Length - 8); i++)
    {
        Console.WriteLine($"I[{i}] : {BinaryPrimitives.ReadInt64BigEndian(testLong.Slice(i))}");
    }