Reputation: 441
Conversion of several values to a byte-string for radio transmission has to avoid unneeded bytes. Using GCC on an ARM target (32 bit) I use "attribute ((packed))". This directive is GCC based (as I read somewhere here) and so not generally portable - which I would prefer. Example:
typedef struct __attribute__ ((packed)) {
uint8_t u8; // (*)
int16_t i16; // (*)
float v;
...
uint16_t cs; // (*)
}valset_t; // valset_t is more often used
valset_t vs;
(*) values would use 4 bytes without the ((packed)) attribute, instead of one or two as desired. Byte-wise access for transmission with:
union{
valset_t vs; // value-set
uint8_t b[sizeof(valset_t)]; // byte array
}vs_u;
using vs_u.b[i] .
Is there a more portable solution in C to perform this task?
Upvotes: 1
Views: 570
Reputation: 213266
Packing/padding isn't standardized, and therefore structs/unions are strictly speaking not portable. #pragma pack(1)
is somewhat more common and supported by many different compilers (including gcc), but it is still not fully portable.
Also please note that padding exists for a reason, these structs with non-standard packing could be dangerous or needlessly inefficient on some systems.
The only 100% portable data type for storing protocols etc is an array of unsigned char
. You can get only get fully portable structs if you write serializer/deserializer routines for them. This naturally comes at the expense of extra code. Example of deserialization:
valset_t data_to_valset (const unsigned char* data)
{
valset_t result;
result.something = ... ;
...
return result;
}
In case of a certain network endianess, you can convert from network endianess to CPU endianess inside the same routine.
Please note that you have to type it out like in the function example above. You cannot write code such as:
unsigned char data[n] = ... ;
valset_t* vs = (valset_t*)data; // BAD
This is bad in multiple different ways: alignment, padding, strict aliasing, endianess and so on.
It is possible to go the other way around though, using a unsigned char*
to inspect or serialize a struct byte by byte. However, doing so doesn't solve the issues of padding bytes or endianess still.
Upvotes: 2