Quantcast
Channel: Active questions tagged gcc - Stack Overflow
Viewing all articles
Browse latest Browse all 22016

GCC compound literal in a C (GCC C11) Macro

$
0
0

After understanding that GCC supports Compound Literals, where an anonymous structure can be filled using a {...} initaliser.

Then consider that gcc accepts (with limitations) variable length structures if the last element is variable length item.

I would like to be able to use macros to fill out lots of tables where most of the data stays the same from compile time and only a few fields change.

My structure are complicated, so here is a simpler working example to start with as a demonstration of the how it is to be used.

#include <stdio.h>typedef unsigned short int uint16_t;typedef unsigned long size_t;#define CONSTANT -20// The data we are storing, we don't need to fill all fields every timetypedef struct dt {    uint16_t    a;    const int   b;} data_t;// An incomplete structure definiton that matches the general shapetypedef struct ct {    size_t      size;    data_t      data;    char        name[];} complex_t;// A typedef to make the code look cleanertypedef complex_t * complex_t_ptr; // A macro to generate instances of objects#define CREATE(X, Y)  (complex_t_ptr)&((struct { \    size_t size;            \    data_t data;            \    char name[sizeof(X)];   \} ) {                       \.size = sizeof(X),          \.data = { .a = Y, .b = CONSTANT }, \.name = X                   \})// Create an array number of structure instance and put pointers those objects into an array// Note each object may be a different size.complex_t_ptr data_table[] = {    CREATE("DATA1", 1),    CREATE("DATA2_LONGER", 2),    CREATE("D3S", 3),};static size_t DATA_TABLE_LEN = sizeof(data_table) / sizeof(typeof(0[data_table]));int main(int argc, char **argv){    for(uint16_t idx=0; idx<DATA_TABLE_LEN; idx++)    {        complex_t_ptr p = data_table[idx];        printf("%15s = (%3u, %3d) and is %3lu long\n", p->name, p->data.a, p->data.b, p->size);    }    return 0;}
$ gcc test_macro.c -o test_macro$ ./test_macro          DATA1 = (  1, -20) and is   6 long   DATA2_LONGER = (  2, -20) and is  13 long            D3S = (  3, -20) and is   4 long

So far so good...

Now, what if we want to create a more complicated object?

//... skipping the rest as hopefully you have the idea by now// A more complicated data structuretypedef struct dt2 {    struct {        unsigned char class[10];        unsigned long start_address;    } xtra;    uint16_t    a;    const int   b;} data2_t;// A macro to generate instances of objects#define CREATE2(X, Y, XTRA)  (complex2_t_ptr)&((struct { \    size_t size;            \    data2_t data;            \    char name[sizeof(X)];   \} ) {                       \.size = sizeof(X),          \.data = { .xtra = XTRA, .a = Y, .b = CONSTANT }, \.name = X                   \})// Again create the tablecomplex2_t_ptr bigger_data_table[] = {    CREATE2("DATA1", 1, {"IO_TBL", 0x123456L}),    CREATE2("DATA2_LONGER", 2, {"BASE_TBL", 0xABC123L}),    CREATE2("D3S", 3, {"MAIN_TBL", 0x555666L << 2}),};//... 

But there is a probem. This does not compile as the compiler (preprocessor) gets confused by the commas between the structure members.The comma in the passed structure members is seen by the macro and it thinks there are extra parameters.

GCC says you can put brackets round terms where you want to keep the commas, like this

MACRO((keep, the, commas))

e.g. In this case, that would be

CREATE_EXTRA("DATA1", 1, ({"IO_TBL", 0x123456L}) )

But that would not work with a structure as we'd get

.xtra = ({"IO_TBL", 0x123456L})

Which is not a valid initaliser.

The other option would be

CREATE_EXTRA("DATA1", 1, {("IO_TBL", 0x123456L)} )

Which results in

.xtra = {("IO_TBL", 0x123456L)}

Which is also not valid

And if we put the braces inside the macro

.xtra = {EXTRA}...CREATE_EXTRA("DATA1", 1, ("IO_TBL", 0x123456L) )

We get the same

Obviously some might say "just pass the elements of XTRA one at a time".Remember this is a simple, very cut down, example and in practice doing that would lose information and make the code much harder to understand, it would be harder to maintain but easer to read if the structures were just copied out longhand.

So the question is, "how to pass compound literal structures to macros as initalisers without getting tripped up by the commas between fields".

NOTE I am stuck with C11 on GCC4.8.x, so C++ or any more recent GCC is not possible.


Viewing all articles
Browse latest Browse all 22016

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>