XPacket is an utility that generates a C struct and two functions for serialize/deserialize it into/from a given payload.
Version 0.3, 02/2018.
Distributed under the GNU Lesser General Public License version 3.
Warnings:
- Macro conflicts are possible.
- If more arguments are used than needed, behavior is undefined.
Todos and possible improvements (in random order):
- Add an automatic delimiter (like '\0') to the arrays
- Check number of arguments in overloading macro.
- Signed type marshalling.
- Graceful error handling.
- Enable/disable inline attribute.
XPacket is an utility that generates a C struct and two functions for serialize/deserialize it into/from a given payload.
When xpacket.h is included, preprocessor uses XPACKET_NAME and XPACKET_STRUCT macro for generate the structure; if these two mandatory macro are not defined when the header is included, a compile-time error is fired. Instead the two functions are generated only if the macro XPACKET_C is defined (and the structure is valid).
XPACKET_NAME is simply the name of the structure, while XPACKET_STRUCT is the list of fields. Different types of field are supported:
- FIELD(type, name, [dim]): a simple variable, or an array if "dim" argument is given.
- FIELD_PTR(type, name, [dim]): a pointer to a variable; or a pointer to an array if "dim" argument is given.
Only unsigned types are currently supported: uint8_t, uint16_t, uint32_t from stdint.h header, that are supposed to have fixed size (operator sizeof is used at compile time).
For example:
#define XPACKET_NAME msg
#define XPACKET_STRUCT \
FIELD(uint16_t, a) \
FIELD(uint8_t, b, 32) \
FIELD_PTR(uint32_t, c)
#include <xpacket.h>
generates:
struct msg {
uint16_t a;
uint8_t b[32];
uint32_t* c;
};
uint16_t serialize_msg(uint8_t*, const struct msg*);
uint16_t deserialize_msg(const uint8_t*, struct msg*);
A decent compiler is necessary for optimize (roll/unroll) the loops. Attributes (such as __attribute__((__packed__))) can be assigned to the structure by simply adding them before include xpacket.h.
The two functions are defined only if macro XPACKET_C is defined; in this way struct and functions declaration can be easily separeted in an header, while the definitions are placed in a C file.
If the XPACKET_OVERLOADING macro is defined, the functions will be simply called "serialize" and "deserialize"; while this may generate name conflicts in the C language, in C++ overloading can solve the possible ambiguity.
The macros can be safely undefined after the header inclusion; it's a common practice redefine their values for include the xpacket header again, in order to generate another different structure and their corresponding functions.
In alternative, the preprocessor can usually run as standalone (option -E with gcc) and generate the C code only once.