C# Converting from byte[] to struct. The byte order is wrong
I was trying to use a 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?
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.
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.
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))
精彩评论