Mutual conversion between C# byte array and object

Posted by Earnan on Sat, 15 Jan 2022 22:00:58 +0100

Demand scenario

Environment Description: VS 2013 Pro net framework 4.5

The received data packet needs to be parsed according to the frame format to obtain byte information with separate meaning
The existing byte information needs to be formed into a frame according to the frame format for subsequent links

If the method of parsing by byte position is adopted, the starting position of each field needs to be calculated, the processing process is cumbersome, and the code adjustment is troublesome when the frame format changes

Try to directly process the memory unit of byte array according to the structure through memory operation. The operation is relatively simple and easy to modify

Namespace

c#, a separate namespace is required to convert byte arrays and structures in memory

using System.Runtime.InteropServices;

Structure definition

A structure with the same length as the byte array needs to be defined in advance to accommodate the byte information in the byte array

[StructLayoutAttribute(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)]
struct DataStruct
{
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
	public byte[] head;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
	public byte[] frameCount;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
	public byte[] len;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
	public byte[] func;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
	public byte[] data;
	[MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)]
	public byte[] check;
}

As for the memory alignment of structures, we know that the memory size of structures is usually an integer multiple of the alignment length. This will cause the memory occupied by the structure to be inconsistent with its content size
Here, we need to allocate the memory of the byte array directly to the structure, and the size of the structure must be exactly the same as that of the byte array, so we need to cancel the memory alignment of the structure
Pack = 1 in the code sets the alignment length to 1, that is, the memory length of the structure is an integer multiple of 1

Byte array to structure

private object BytesToDataStruct(byte[] bytes, Type type)
{
    //DataStruct data = new DataStruct();

    int size = Marshal.SizeOf(type);

    if (size > bytes.Length)
    {
        return null;
    }

    IntPtr structPtr = Marshal.AllocHGlobal(size);
    Marshal.Copy(bytes, 0, structPtr, size);
    object obj = Marshal.PtrToStructure(structPtr, type);
    Marshal.FreeHGlobal(structPtr);
    return obj;
}

Code Description:

  • First, obtain the memory length size required by the structure type to judge whether it can be converted
  • Open up a memory space with a length of size
  • Copy byte array contents to memory space
  • Assign this memory space to object obj
  • Release the memory space pointer and return the object obj
  • Next, you can convert obj to any type of struct

The use method is

DataStruct frame = (DataStruct)BytesToDataStruct(bytes, typeof(DataStruct));

Structure to byte array

private byte[] StructToBytes(object anyStruct)
{
    int size = Marshal.SizeOf(anyStruct);
    IntPtr bytesPtr = Marshal.AllocHGlobal(size);
    Marshal.StructureToPtr(anyStruct, bytesPtr, false);
    byte[] bytes = new byte[size];
    Marshal.Copy(bytesPtr, bytes, 0, size);
    Marshal.FreeHGlobal(bytesPtr);

    return bytes;
}

Code Description:

  • Gets the size of the structure
  • Open up a memory space with a length of size
  • Assign the contents of the memory space of the structure to the newly opened memory space
  • Define a byte array of size
  • Copy the contents of the memory space to the byte array
  • Free memory space pointer and return byte array

The use method is

byte[] bytes = StructToBytes(frame)

Topics: C# Skills