Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enforce two structs to have same size at compile time?

Tags:

c

embedded

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).

like image 293
ttemple Avatar asked Oct 02 '18 12:10

ttemple


People also ask

Does sizeof work on structs?

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.

What is structure padding in C++?

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.

Can the size of a struct change?

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.

How do I get the size of a structure in C++?

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.


1 Answers

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.

like image 62
StoryTeller - Unslander Monica Avatar answered Sep 19 '22 12:09

StoryTeller - Unslander Monica