ben23f
ben23f

Reputation: 47

How to convert a variable size struct to char array

I am trying to serialize a structure for sending as a UDP message. The issue I am having is that the structure contains a variable length array of sub-structures as below:

struct SubStruct
{
    short val1;
    short val2;
};

struct Message
{
    short numSubStructs;
    SubStruct* structs;
};

The method I use for sending my fixed length messages is to cast the struct to a unsigned char*. Below MSG_LENGTH is equal to sizeof(short) + numSubStructs * sizeof(SubStruct)

send(socket, reinterpret_cast<unsigned char*>(&someMessage), MSG_LENGTH);

This works fine for all my fixed length messages but not for the variable length messages. Looking at the data sent out over the socket, I'm pretty sure it is sending the actual address of the structs pointer.

My question is, is there a way of serializing this kind of structure other than looping through the pointer (array) and appending to some buffer?

Thanks

Upvotes: 0

Views: 660

Answers (2)

Matthew Fisher
Matthew Fisher

Reputation: 2336

I'm not aware of an elegant way to do this in C++. There are some ugly ways however. Basically, allocate a buffer large enough to hold the entire 'unrolled' structure and sub-structure. If the last member of the struct is the variable sized element then it is not too bad to maintain. If there are multiple nested structures then it gets to be unwieldy.

Here is a C style example.

struct example{
   int array_length;
   some_struct array[1];  // beware of padding in structure between the fields
}

int number_of_structs = 2;
example* ptr = malloc(sizeof(int)+ number_of_structs*sizeof(some_struct));
ptr->array_lenth = number_of_structs;
ptr->array[0].first_field = 1;
ptr->array[1].first_field = 2;

send(socket, ptr, sizeof(int)+ number_of_structs*sizeof(some_struct));

There are also some (nonstandard) ways to do this with zero length arrays.

Upvotes: 0

dgnuff
dgnuff

Reputation: 3557

Try something like this:

char *serializedMessage = new char[sizeof(short) + someMessage.numSubStructs * sizeof(SubStruct)];
// Error check here

// Insert the count of structs
memcpy(serializedMessage, &someMessage.numSubStructs, sizeof(short));
// Copy the structs themselves.
memcpy(&serializedMessage[sizeof(short)], someMessage.structs,
        someMessage.numSubStructs * sizeof(SubStruct));

// Transmit serializedMessage

delete[] serializedMessage;

NOTE This does not pay attention to the endianess of the data, so it is highly likely to fail if the source and target machines have different endianess.

Upvotes: 1

Related Questions