Archive

Posts Tagged ‘C-Sharp’

C# and Serializing Structs to byte arrays

July 2nd, 2009 David 6 comments

So I have a application in C# that is communicating to something else via UDP messages. The messages are byte packed arrays of data. There are several bytes of header and then N bytes of data whos format is described in the header. I might send several Ints, or a string, or whatever.

This is pretty easy to handle in C/C++ as you can get raw pointers to everything. So if each message type is a struct, I can get a char* to the address of the struct and just read N bytes and send that out.

The problem on the C# end is this isnt so easy. If I want to pull messages apart and put them back into structs I have to do this manually each multi byte field at a time. So I was left with a function call for each message type to serialize it, and then another to deserialize it, each one having to know exactly what was in each message, so if I changed a message I’d have to edit all the handling functions. What I needed was a way to jsut get the raw bytes the in the received array into a struct of the right type, and vice versa. Fortunately there are some tricky ways to make this super easy.

First, we have to make sure the structs we declare in C# and packed. Here is an example:

using System.Runtime.InteropServices;

[StructLayout(LayoutKind.Sequential, Pack=1)]
struct msg1{
     int a;
     int b
     short c;
}

This will ensure there are no gaps between elements in the struct.

Next, we need a way to take an array of Bytes and copy it directly into the struct:

public static T DeserializeMsg< T >(Byte[] data) where T : struct
        {
            int objsize = Marshal.SizeOf(typeof(T));
            IntPtr buff = Marshal.AllocHGlobal(objsize);

            Marshal.Copy(data, 0, buff, objsize);

            T retStruct = (T)Marshal.PtrToStructure(buff, typeof(T));

            Marshal.FreeHGlobal(buff);

            return retStruct;
        }

Lets say we have a msg1 struct populated and we want to send that out over UDP. We need to serialize it back to raw bytes. This function will do just that:

public static Byte[] SerializeMessage< T >(T msg) where T : struct
        {
            int objsize = Marshal.SizeOf(typeof(T));
            Byte[] ret = new Byte[objsize];

            IntPtr buff = Marshal.AllocHGlobal(objsize);

            Marshal.StructureToPtr(msg, buff, true);

            Marshal.Copy(buff, ret, 0, objsize);

            Marshal.FreeHGlobal(buff);

            return ret;
        }

Thats it!

qrcode