How can I map a stream of bytes to a struct type?

134 Views Asked by At

I have code that reads a stream of bytes from a serial port using a propriety protocol. In the end I have a array of bytes that represents a carefully aligned structure sent by the other end of the connection. Part of that struct is a an array of other structs. C# does not seem to allow fixed arrays with anything other than base types. In C it is simple. I can craft a struct definition including the fixed array of structs and just cast a pointer of the type to the beginning of the byte array. I can then dereference the pointer to access individual members. Simple. What is the best way of doing this in C#?

e.g. In C:

byte serialBuff[40];  // holds an array of bytes containing the message I want;
typedef struct { char x; char y } point_t;
typedef struct { char trId; char ack, point_t points[3]; } message_t; 
// message_t has the following representation in my byte buffer:
//                point[0], point[1], point[2]
// each element is a byte
// --------------------------------------------
// | trId | ack | x  | y  | x  |  y | x  | y  |
// --------------------------------------------
// ^
// serialBuff

To access this message correctly all I need do is:

message_t *myMessage = (message_t *)serialBuff;

Is there any way to do this in C#, or do I have to read in each byte and copy it into individual struct or class members? So far I have written code to read in the first part of the message then another to read in the array of points and copy them to a struct. Very ugly and inefficient I think - but it works!

1

There are 1 best solutions below

0
xVice1337 On

I guess the unsafe keyword could work here:

(Thrown together quickly so you get the idea)

unsafe struct Point
{
    public byte x;
    public byte y;
}

unsafe struct Message
{
    public byte trId;
    public byte ack;
    public fixed Point points[3]; // Using fixed array
}

class Program
{
    static unsafe void Main(string[] args)
    {
        byte[] serialBuffer = new byte[40]; // Your byte buffer

        fixed (byte* pBuffer = serialBuffer)
        {
            Message* myMessage = (Message*)pBuffer;

            // Accessing individual members
            byte trId = myMessage->trId;
            byte ack = myMessage->ack;

            Point point0 = myMessage->points[0];
            byte x0 = point0.x;
            byte y0 = point0.y;

            // Similar access for other points
        }
    }
}