One style minimizes the amount of data which is copied from place to place, at the expense of ``extra'' code that you have to generate. For example, say we have a message that we want to fill with the following structure,
struct TestStruct { int a; int b; bool c; };
The most efficient way, from a performance perspective, to set up and send this message is,
TestStruct* ts = (TestStruct*) msg->getData(); ts->a = 1; ts->b = 2; ts->c = false; msg->setSize(sizeof(TestStruct);
Similarly, if we want to unpack a TestStruct instance from a message, we could do,
TestStruct* ts = (TestStruct*) msg->getData(); if (msg->getSize() < sizeof(testStruct)) return false; a = ts->a; b = ts->b; c = ts->c;
As a convenience, if you do not mind that there is an extra copying of the data, you can use the convenience templated methods Message::getStruct and Message::setStruct. For example, to copy the message data to a destination structure, you could simply do,
TestStruct ts; if (!msg->getStruct<TestStruct>(&ts)) return false;
And to copy a source structure to the message data you can do,
TestStruct ts; if (!msg->setStruct<TestStruct>(&ts)) return false;
This style is much more ``compact'' than dealing with the message data directly, but that compactness does come at the price of an extra message copy.
Remember that messages are ultimately just a vector of bytes. There are several things to watch out for when directly using C++ structures to set and get message data.
First, you must be aware that different compilers can ``align'' structure elements differently. For example, some compilers will pad a one byte type such as a unsigned char out to four bytes when preceding a four byte integer. Others will not. So a structure which has the elements ``unsigned char'' followed by an ``int'' is much more dangerous than the structure which has the elements ``int'' followed by an ``unsigned char''.
Even more importantly, remember that even under the best of circumstances, only ``flat'' structures can be dealt with properly by the message convenience functions. A flat structure cannot be a class, and cannot contain pointers of any kind. For example, this is a flat structure,
struct FlatStruct { int a, b; float c[24]; }
But, this is not a flat structure,
struct UnflatStruct { int a, b; float *c; }
If you have a structure that is not flat that you want to send, you will have to manage the packing and unpacking yourself. The simplest example is the sending and receiving of a variable length string.
On the sending side, one way to package a string ( char* s) is this,
int len = strlen(s); if (len > msg->getMaxSize()) // truncate strings which are too large len = msg->getMaxSize()-1; memcpy(msg->getData(), s, len); msg->getData()[len] = '\0'; msg->setSize(len+1);
On the receiving side, you simply unpack the string by doing,
char* s = (char*) msg->getData();
Packaging more complicated structures, such as multiple strings, or structures containing variable length vectors of number, has to be done ``by hand,'', i.e., you must assemble the data vector component by component. On the plus side, assembling the data vector by hand this way alleviates the problem of structure alignment differences between compilers.