|
|
|
How do I copy a structure to a byte array or vice versa?
Written: 6/19/2002 Updated: 6/20/2002
There are a couple different options. The most .NET friendly way would be to use binary serialization.
This, however, would give you the result in a proprietary format, which doesn't match the actual memory
layout of the structure, which usually is what you want.
Another option is to use the Marshal class to allocate a piece of unmanaged heap memory, and then
read and write to that using PtrToStructure(), StructureToPtr() and Copy().
| C# |
struct MyStruct
{
public static readonly int SIZEOF_MYSTRUCT = Marshal.SizeOf( typeof(MyStruct) ); // 24
public long l;
public short s;
// 2 byte padding
public int i;
public bool f;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public byte[] b;
}
// ...
MyStruct ms;
byte[] rawData = new byte[MyStruct.SIZEOF_MYSTRUCT];
IntPtr pBlob = IntPtr.Zero;
ms.l = 7;
ms.s = 6;
ms.i = 5;
ms.f = true;
ms.b = new byte[4];
for ( int i = 0; i < 4; i++ )
ms.b[i] = (byte)(i+1);
try {
pBlob = Marshal.AllocHGlobal( MyStruct.SIZEOF_MYSTRUCT );
Marshal.StructureToPtr( ms, pBlob, false );
Marshal.Copy( pBlob, rawData, 0, MyStruct.SIZEOF_MYSTRUCT );
}
finally {
if ( pBlob != IntPtr.Zero ) Marshal.FreeHGlobal( pBlob );
}
// Prints: 07 00 00 00 00 00 00 00 06 00 00 00 05 00 00 00 01 00 00 00 01 02 03 04
// | l | | s | |pad| | i | | f | |b[0]-b[3]|
for ( int i = 0; i < rawData.Length; i++ ) {
Console.Write( "{0:X2} ", rawData[i] );
rawData[i] *= 2;
}
Console.WriteLine();
pBlob = IntPtr.Zero;
try {
pBlob = Marshal.AllocHGlobal( MyStruct.SIZEOF_MYSTRUCT );
Marshal.Copy( rawData, 0, pBlob, MyStruct.SIZEOF_MYSTRUCT );
ms = (MyStruct)Marshal.PtrToStructure( pBlob, typeof(MyStruct) );
}
finally {
if ( pBlob != IntPtr.Zero ) Marshal.FreeHGlobal( pBlob );
}
// Prints: l=14, s=12, i=10, f=True, b=[2,4,6,8]
Console.WriteLine( "l={0}, s={1}, i={2}, f={3}, b=[{4},{5},{6},{7}]",
ms.l, ms.s, ms.i, ms.f, ms.b[0], ms.b[1], ms.b[2], ms.b[3] );
|
| VB.NET |
Structure MyStruct
Public Shared ReadOnly SIZEOF_MYSTRUCT As Integer
Shared Sub New()
SIZEOF_MYSTRUCT = Marshal.SizeOf(GetType(MyStruct)) ' 24
End Sub
Public l As Long
Public s As Short
' 2 byte padding
Public i As Integer
Public f As Boolean
<MarshalAs(UnmanagedType.ByValArray, SizeConst:=4)> _
Public b() As Byte
End Structure
' ...
Dim ms As MyStruct
Dim rawData(MyStruct.SIZEOF_MYSTRUCT - 1) As Byte
Dim pBlob As IntPtr
Dim i As Integer
ms.l = 7
ms.s = 6
ms.i = 5
ms.f = True
ms.b = New Byte(3) {}
ms.b(0) = 1 : ms.b(1) = 2: ms.b(2) = 3 : ms.b(3) = 4
Try
pBlob = Marshal.AllocHGlobal(MyStruct.SIZEOF_MYSTRUCT)
Marshal.StructureToPtr(ms, pBlob, False)
Marshal.Copy(pBlob, rawData, 0, MyStruct.SIZEOF_MYSTRUCT)
Finally
If Not pBlob.Equals(IntPtr.Zero) Then Marshal.FreeHGlobal(pBlob)
End Try
' Prints: 07 00 00 00 00 00 00 00 06 00 00 00 05 00 00 00 01 00 00 00 01 02 03 04
' | l | | s | |pad| | i | | f | |b(0)-b(3)|
For i = 0 To rawData.Length - 1
Console.Write("{0:X2} ", rawData(i))
rawData(i) *= CByte(2)
Next
Console.WriteLine()
pBlob = IntPtr.Zero
Try
pBlob = Marshal.AllocHGlobal(MyStruct.SIZEOF_MYSTRUCT)
Marshal.Copy(rawData, 0, pBlob, MyStruct.SIZEOF_MYSTRUCT)
ms = CType(Marshal.PtrToStructure(pBlob, GetType(MyStruct)), MyStruct)
Finally
If Not pBlob.Equals(IntPtr.Zero) Then Marshal.FreeHGlobal(pBlob)
End Try
' Prints: l=14, s=12, i=10, f=True, b=[2,4,6,8]
Console.WriteLine("l={0}, s={1}, i={2}, f={3}, b=[{4},{5},{6},{7}]", _
ms.l, ms.s, ms.i, ms.f, ms.b(0), ms.b(1), ms.b(2), ms.b(3) )
|
In C# it can also be done with pointers in an unsafe code block. Note the difference in
the result in the code above and below. Unsafe code isn't affected by structure layout
or marshaling attributes. The order of the members is rearranged for optimal layout,
the byte array has to be flattened to separate members, and the bool is treated as a single byte.
| C# |
struct MyStruct
{
public long l;
public short s;
public int i;
public bool f;
public byte b0, b1, b2, b3;
}
// ...
MyStruct ms;
byte[] rawData = new byte[sizeof(MyStruct)]; // 20
ms.l = 7;
ms.s = 6;
ms.i = 5;
ms.f = true;
ms.b0 = 1; ms.b1 = 2; ms.b2 = 3; ms.b3 = 4;
fixed ( byte* pData = rawData )
*((MyStruct*)pData) = ms;
// Prints: 07 00 00 00 00 00 00 00 05 00 00 00 06 00 01 01 02 03 04 ??
// | l | | i | | s || f|| b0-b3 | | garbage |
for ( int i = 0; i < rawData.Length; i++ ) {
Console.Write( "{0:X2} ", rawData[i] );
rawData[i] *= 2;
}
Console.WriteLine();
fixed ( byte* pData = rawData )
ms = *((MyStruct*)pData);
// Prints: l=14, s=12, i=10, f=True, b0=2, b1=4, b2=6, b3=8
Console.WriteLine( "l={0}, s={1}, i={2}, f={3}, b0={4}, b1={5}, b2={6}, b3={7}",
ms.l, ms.s, ms.i, ms.f, ms.b0, ms.b1, ms.b2, ms.b3 );
|
|