0

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

ben23f
  • 47
  • 5
  • You cannot have variable sized types in C++. –  Aug 28 '18 at 23:32
  • @NeilButterworth Yes I understand this. I suppose I should clarify, when I say variable sized, I mean the pointer points to some run-time allocated array. – ben23f Aug 29 '18 at 00:11

2 Answers2

1

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.

dgnuff
  • 3,195
  • 2
  • 18
  • 32
  • 1
    Thanks will give this a go. I'm aware of endianess, just left it out of the question for simplicity. – ben23f Aug 29 '18 at 00:13
0

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.

Matthew Fisher
  • 2,258
  • 2
  • 14
  • 23