views:

40

answers:

3

I was trying to using struct to parse socket data when implement a UDP based protocol. And I searched and I can use these 2 functions to convert between byte[] and struct:

 byte[] StructToBytes(object structObj)
    {
        int size = Marshal.SizeOf(structObj);
        IntPtr buffer = Marshal.AllocHGlobal(size);
        try
        {
            Marshal.StructureToPtr(structObj, buffer, false);
            byte[] bytes = new byte[size];
            Marshal.Copy(buffer, bytes, 0, size);
            return bytes;
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }

    }

    static object BytesToStruct(byte[] bytes, Type strcutType, int offset = 0)
    {
        int size = Marshal.SizeOf(strcutType);
        IntPtr buffer = Marshal.AllocHGlobal(size);
        try
        {
            Marshal.Copy(bytes, offset, buffer, size);
            return Marshal.PtrToStructure(buffer, strcutType);
        }
        finally
        {
            Marshal.FreeHGlobal(buffer);
        }
    }

Then I had this problem:

//I defined a simple struct with an ushort member
    [StructLayout(LayoutKind.Sequential, Pack = 2)]
    struct S
    {
        public ushort a;
    }

    //Then I define a byte[]
    byte[] bArr;
    bArr[0] = 0;
    bArr[1] = 1;

    //Convert to struct
    S s = (S)BytesToStruct(bArr, typeof(S));
    //Then s.a = 0x0100 not 0x0001

And struct to byte[] is just the same. The 2 bytes of ushort are reversed. How do I solve this problem?

+1  A: 

There's a difference between network byte order and host byte order.

Typically, in C at least, you use ntohl(), ntohs() and friends to convert network byte order to your host order when reading from a socket.

Frank Shearar
+1  A: 

Most processors these days use Little-Endian byte ordering (Least significant byte comes first). Network byte ordering is traditional Big-Endian, so you usually need to mirror the byte order. You can check the endianness of the system with System.BitConverter.IsLittleEndian

The .Net equivalent of ntohs() Frank mentioned is located (oddly) at System.Net.IPAddress.NetworkToHostOrder()

You could also write your own mechanism to read the bytes in the correct order directly, using bit shifting and logical OR.

Mark H
+1  A: 

The problem is to do with the endianness of short on your system. Have a look at this question about endianness, which may provide some pointers (pun unintentional).

Also, I would suggest making BytesToStruct generic in the type of the struct:

static S BytesToStruct<S>(byte[] bytes, int offset = 0)

so it could be called with

BytesToStruct<S>(bArr)

rather than as at present

(S)BytesToStruct(bArr, typeof(S))
AakashM