I have defined two data structures that must remain the same size as each other for the application to function properly. The struct's are used to communicate between a PC and a DSP. The DSP code is in 'C', the PC side in C++.
for example:
struct inbound_data{
int header[5];
float val1;
float val2;
int trailer[3];
};
struct outbound_data{
int header[5];
int reply1;
int reply2;
float dat1;
float dat2;
int filler[1];
}
later I will do something like:
int tx_block[sizeof(outbound_data)];
int rx_block[sizeof(inbound_data)];
These arrays will be passed to the communication peripherals to transmit and receive between the devices.
Because of how the hardware works, it is essential that the size of the two structs match, so that the buffers are of equal size. This is easy enough to assure with proper care, but occasionally through the design cycle, the data structures get modified. If one is not extremely careful, and aware of the requirement that the structures stay the same size (and be reflected in the PC side code as well), chaos ensues.
I would like to find a compile time way to have the code not build if one of the structures gets modified so that it does not match the size of the other structure.
Is this possible somehow in 'standard' C to check the sizes at compile time and fail if they are different? (I think my compiler is at least C99, maybe not 11).
The sizeof for a struct is not always equal to the sum of sizeof of each individual member. This is because of the padding added by the compiler to avoid alignment issues. Padding is only added when a structure member is followed by a member with a larger size or at the end of the structure.
Structure padding is a concept in C that adds the one or more empty bytes between the memory addresses to align the data in memory.
Rearranging the fields in a struct can change the size of the struct . It is possible to minimize padding anomalies if the fields are arranged in such a way that fields of the same size are grouped together.
In 32 bit processor, it can access 4 bytes at a time which means word size is 4 bytes. Similarly in a 64 bit processor, it can access 8 bytes at a time which means word size is 8 bytes. Structure padding is used to save number of CPU cycles. Let's see what compiler is giving using the sizeof() operator.
If you must use C99, then I too like Swordfish would suggest a macro. The way to make one which can appear anywhere, and would not introduce any objects for the optimizer to remove, is to put the invalid array in a typedef
. So a more general purpose static assertion would look this:
#define CONCAT_(A,B) A##B
#define CONCAT(A,B) CONCAT_(A,B)
#define MY_STATIC_ASSERT(p, msg) typedef char CONCAT(dummy__,__LINE__) [(p) ? 1 : -1]
It's designed to mimic _Static_assert
. The message is passed in with the hopes of a compiler diagnostic showing it. An example for its usage is here.
Which produces:
main.cpp:4:54: error: size of array 'dummy__13' is negative
#define MY_STATIC_ASSERT(p, msg) typedef char CONCAT(dummy__,__LINE__) [(p) ? 1 : -1]
^~~~~~~
main.cpp:2:22: note: in definition of macro 'CONCAT_'
#define CONCAT_(A,B) A##B
^
main.cpp:4:47: note: in expansion of macro 'CONCAT'
#define MY_STATIC_ASSERT(p, msg) typedef char CONCAT(dummy__,__LINE__) [(p) ? 1 : -1]
^~~~~~
main.cpp:13:1: note: in expansion of macro 'MY_STATIC_ASSERT'
MY_STATIC_ASSERT(sizeof(struct foo) == sizeof(struct baz), "Do not match!");
And all the way down there you can see the static assertion with the message.
As an afterthought, you can change dummy__
to please_check_line_
will will produce the more descriptive please_check_line_13
above.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With