none
Convert big endian to little endian RRS feed

  • Question

  • What is the best way to convert a ulong (UInt64) big endian number to little endian in C#?

    Tuesday, August 21, 2007 8:33 AM

Answers

  • If you are only converting a few numbers, you could use the BitConverter class to turn the Int64 into an array of 8 bytes and then juggle those bytes around, and finally use BitConverter to turn the bytes back into an Int64.

    If you are converting lots of numbers, and BitConverter is too slow AND you don't mind using unsafe code, this might be the fastest way:



    static void Main(string[] args)
    {
        long[] array = new long[] { 0x0102030405060708, 0x1122334455667788 };

        unsafe
        {
            fixed (long* p = array)
            {
                byte* q = (byte*)p;

                for (int i = 0; i < array.Length; ++i)
                {
                    for (int j = 0; j < 4; ++j)
                    {
                        byte temp = q[j];
                        q[j] = q[7-j];
                        q[7-j] = temp;
                    }

                    q += 8;
                }
            }
        }

        foreach (long n in array)
        {
            Console.WriteLine(n.ToString("x"));
        }
    }

     



    NOTE: I'm not sure I'm swapping the byte values around correctly in the inner loop. Please correct it appropriately if I'm not! Smile

    Tuesday, August 21, 2007 9:20 AM
  • Here's the code ready for you to put in your own manipulation where stated by the comments:



    static void Main(string[] args)
    {
        long[] array = new long[] { 0x0123456789abcdef };

        unsafe
        {
            fixed (long* p = array)
            {
                byte* q = (byte*)p;

                for (int i = 0; i < array.Length; ++i)
                {
                    // The 8 bytes of the next Int64 are now available
                    // as q[0] .. q[7].
                    // Manipulate them as you wish.

                    q += 8;  // On to the next Int64.
                }
            }
        }

        foreach (long n in array)
        {
            Console.WriteLine(n.ToString("x"));
        }
    }

     


    Tuesday, August 21, 2007 10:20 AM
  • I like the following approach:

     

     

    /// <summary>

    /// Swaps the byte order of an <see cref="Int64"/>.

    /// </summary>

    /// <param name="value"><see cref="Int64"/> to swap the bytes of.</param>

    /// <returns>Byte order swapped <see cref="Int64"/>.</returns>

    private static Int64 swapByteOrder(Int64 value)

    {

    UInt64 uvalue = (UInt64)value;

    UInt64 swapped = ( (0x00000000000000FF) & (uvalue >> 56)

    | (0x000000000000FF00) & (uvalue >> 40)

    | (0x0000000000FF0000) & (uvalue >> 24)

    | (0x00000000FF000000) & (uvalue >> 8)

    | (0x000000FF00000000) & (uvalue << 8)

    | (0x0000FF0000000000) & (uvalue << 24)

    | (0x00FF000000000000) & (uvalue << 40)

    | (0xFF00000000000000) & (uvalue << 56));

    return (Int64)swapped;

    }

     

    It has the benefits of not requiring pointers, and thus can be used with partially trusted code. Since it just uses bit shift and logical operators, it's very fast. My initial tests after a number of runs look similar to this:

     

    Generating 1000 Int64 values...

     

    Bit shift: 100 iterations of swapping 1000 values took 3 ms.
    Bit shift: 1000 iterations of swapping 1000 values took 39 ms.
    Bit shift: 10000 iterations of swapping 1000 values took 369 ms.
    Bit shift: 100000 iterations of swapping 1000 values took 3598 ms.

     

    Pointer loop: 100 iterations of swapping 1000 values took 6 ms.
    Pointer loop: 1000 iterations of swapping 1000 values took 66 ms.
    Pointer loop: 10000 iterations of swapping 1000 values took 661 ms.
    Pointer loop: 100000 iterations of swapping 1000 values took 6645 ms.

     

    HostToNetworkOrder: 100 iterations of swapping 1000 values took 3 ms.
    HostToNetworkOrder: 1000 iterations of swapping 1000 values took 40 ms.
    HostToNetworkOrder: 10000 iterations of swapping 1000 values took 408 ms.
    HostToNetworkOrder: 100000 iterations of swapping 1000 values took 4061 ms.

     

    Array.Reverse: 100 iterations of swapping 1000 values took 18 ms.
    Array.Reverse: 1000 iterations of swapping 1000 values took 217 ms.
    Array.Reverse: 10000 iterations of swapping 1000 values took 1939 ms.
    Array.Reverse: 100000 iterations of swapping 1000 values took 20082 ms.


    Done!

     

    You can adapt it for your needs, and find other examples of reversing the byte order of numeric values (including Doubles) here: http://www.codeplex.com/GeoAPI/SourceControl/FileView.aspx?itemId=187136&changeSetId=15028

    Friday, January 18, 2008 1:45 AM

All replies

  • If you are only converting a few numbers, you could use the BitConverter class to turn the Int64 into an array of 8 bytes and then juggle those bytes around, and finally use BitConverter to turn the bytes back into an Int64.

    If you are converting lots of numbers, and BitConverter is too slow AND you don't mind using unsafe code, this might be the fastest way:



    static void Main(string[] args)
    {
        long[] array = new long[] { 0x0102030405060708, 0x1122334455667788 };

        unsafe
        {
            fixed (long* p = array)
            {
                byte* q = (byte*)p;

                for (int i = 0; i < array.Length; ++i)
                {
                    for (int j = 0; j < 4; ++j)
                    {
                        byte temp = q[j];
                        q[j] = q[7-j];
                        q[7-j] = temp;
                    }

                    q += 8;
                }
            }
        }

        foreach (long n in array)
        {
            Console.WriteLine(n.ToString("x"));
        }
    }

     



    NOTE: I'm not sure I'm swapping the byte values around correctly in the inner loop. Please correct it appropriately if I'm not! Smile

    Tuesday, August 21, 2007 9:20 AM
  • Thanks for the reply, but this doesn't provide the correct numbers and I don't really understand what you are trying to do.  I think the output should be:

    72623859790382856

    1234605616436508552

     

    I have the bytes broken up and I've tried to use shift operators to get the value:

      ulong result = (ulong)((byte1 << 56) + (byte2 << 48) + (byte3 << 40) + (byte4 << 32) + (byte5 << 24) + (byte6 << 16) + (byte7 << 8) + byte8);

     

    However, the shift doesn't convert properly for 32 and higher.  Is there an easier way for me to assemble the bytes manually?

    Tuesday, August 21, 2007 9:55 AM
  • Yes, the inner loop in the code that I gave has a pointer 'q' that is pointing to the first of 8 bytes in one of the Int64 values. You can access those 8 bytes by writing q[0], q[1], ..., qDevil, q[7]

    You can manipulate those bytes however you want. The innermost loop in the code I gave simply reverses the order of the 8 bytes (I don't know what the correct reordering is).

    You need to swap around the 8 bytes to give the right order.

    When you say you think the output should be

    72623859790382856

    1234605616436508552


    What input was that for? The 0x11223344556677 and 0x01020304050607 values I gave?

    Put another way, if the input value is 0x0123456789abcdef, what should the output be?

    Tuesday, August 21, 2007 10:13 AM
  • Here's the code ready for you to put in your own manipulation where stated by the comments:



    static void Main(string[] args)
    {
        long[] array = new long[] { 0x0123456789abcdef };

        unsafe
        {
            fixed (long* p = array)
            {
                byte* q = (byte*)p;

                for (int i = 0; i < array.Length; ++i)
                {
                    // The 8 bytes of the next Int64 are now available
                    // as q[0] .. q[7].
                    // Manipulate them as you wish.

                    q += 8;  // On to the next Int64.
                }
            }
        }

        foreach (long n in array)
        {
            Console.WriteLine(n.ToString("x"));
        }
    }

     


    Tuesday, August 21, 2007 10:20 AM
  • Thanks for the help.  And you're right.  I think your code does produce the correct result.

     

    Tuesday, August 21, 2007 10:47 AM
  • I like the following approach:

     

     

    /// <summary>

    /// Swaps the byte order of an <see cref="Int64"/>.

    /// </summary>

    /// <param name="value"><see cref="Int64"/> to swap the bytes of.</param>

    /// <returns>Byte order swapped <see cref="Int64"/>.</returns>

    private static Int64 swapByteOrder(Int64 value)

    {

    UInt64 uvalue = (UInt64)value;

    UInt64 swapped = ( (0x00000000000000FF) & (uvalue >> 56)

    | (0x000000000000FF00) & (uvalue >> 40)

    | (0x0000000000FF0000) & (uvalue >> 24)

    | (0x00000000FF000000) & (uvalue >> 8)

    | (0x000000FF00000000) & (uvalue << 8)

    | (0x0000FF0000000000) & (uvalue << 24)

    | (0x00FF000000000000) & (uvalue << 40)

    | (0xFF00000000000000) & (uvalue << 56));

    return (Int64)swapped;

    }

     

    It has the benefits of not requiring pointers, and thus can be used with partially trusted code. Since it just uses bit shift and logical operators, it's very fast. My initial tests after a number of runs look similar to this:

     

    Generating 1000 Int64 values...

     

    Bit shift: 100 iterations of swapping 1000 values took 3 ms.
    Bit shift: 1000 iterations of swapping 1000 values took 39 ms.
    Bit shift: 10000 iterations of swapping 1000 values took 369 ms.
    Bit shift: 100000 iterations of swapping 1000 values took 3598 ms.

     

    Pointer loop: 100 iterations of swapping 1000 values took 6 ms.
    Pointer loop: 1000 iterations of swapping 1000 values took 66 ms.
    Pointer loop: 10000 iterations of swapping 1000 values took 661 ms.
    Pointer loop: 100000 iterations of swapping 1000 values took 6645 ms.

     

    HostToNetworkOrder: 100 iterations of swapping 1000 values took 3 ms.
    HostToNetworkOrder: 1000 iterations of swapping 1000 values took 40 ms.
    HostToNetworkOrder: 10000 iterations of swapping 1000 values took 408 ms.
    HostToNetworkOrder: 100000 iterations of swapping 1000 values took 4061 ms.

     

    Array.Reverse: 100 iterations of swapping 1000 values took 18 ms.
    Array.Reverse: 1000 iterations of swapping 1000 values took 217 ms.
    Array.Reverse: 10000 iterations of swapping 1000 values took 1939 ms.
    Array.Reverse: 100000 iterations of swapping 1000 values took 20082 ms.


    Done!

     

    You can adapt it for your needs, and find other examples of reversing the byte order of numeric values (including Doubles) here: http://www.codeplex.com/GeoAPI/SourceControl/FileView.aspx?itemId=187136&changeSetId=15028

    Friday, January 18, 2008 1:45 AM
  • Yep, that's a much better way to do it.
    Friday, January 18, 2008 4:12 PM
  • Here is a more careful look at the issue than above...

     

    http://vectordotnet.blogspot.com/2008/01/swapping-byte-encoding-order-of-multi.html

     

     

    Monday, January 21, 2008 6:01 PM
  • Does anybody have a bit shift for a 14-byte swap endian? The above code works great, but have a special case of needing to do a size of 14. I have included the macros we use.

    #define endian_swap2byte(x) \

      x =  ((x & 0x00FF) << 8) | \
        ((x & 0xFF00) >> 8)


    #define endian_swap4byte(x) \
      x = ((x & 0x000000FF) << 24) | \
        ((x & 0x0000FF00) << 8) | \
        ((x & 0x00FF0000) >> 8) | \
        ((x & 0xFF000000) >> 24)


    #define endian_swap8byte(x) \
      x = (x>>56) | \
        ((x<<40) & 0x00FF000000000000) | \
        ((x<<24) & 0x0000FF0000000000) | \
        ((x<<8)  & 0x000000FF00000000) | \
        ((x>>8)  & 0x00000000FF000000) | \
        ((x>>24) & 0x0000000000FF0000) | \
        ((x>>40) & 0x000000000000FF00) | \
        (x<<56)

    Tuesday, April 22, 2008 4:39 PM