Search code examples
cavr

Macro to set up statically allocated struct in C


I have the following C code which creates a struct describing a FIFO, and separately defines an array to hold the actual data for said FIFO. This is part of a basic I2C/TWI driver that i'm writing and it would be preferable to have a way of doing this more concisely, such as with a function which takes a size as a parameter.

    twi_fifo_t fifo;
    twi_entry_t fifodata[64];

    fifo.push = 0;
    fifo.pull = 0;
    fifo.next_cmd = 0;
    fifo.size_mask = ~(0xFFFF<<6);
    fifo.data = fifodata;

However, I would like these to be statically allocated as there is no foreseeable reason why they should be created, destroyed, or changed during runtime.

My understanding is that if i created the FIFO and data array in a function, i would need to use malloc() to allocate them, since their location cant be decided at compile time. This seemed to warrant a macro, which lead to the second piece of code.

#define twi_make_fifo(name, size)\
    twi_fifo_t name;\
    twi_entry_t name##_data[1<<size];\
    name.push = 0;\
    name.pull = 0;\
    name.next_cmd = 0;\
    name.size_mask = ~(0xFFFF<<size);\
    name.data = name##_data;

The macro solution seems a bit distasteful, is there some obvious way of simplifying this operation that I'm forgetting about?


Solution

  • If your FIFOs have varying names and sizes, and if you want to avoid separate, explicit code for declaration and initialization of the data structures for each one, then there are only two alternatives: write a reusable function that does the job (which will need to perform dynamic allocation, and therefore place an obligation to free on the caller), or write a reusable function-like macro.

    The macro solution seems a bit distasteful, is there some obvious way of simplifying this operation that I'm forgetting about?

    Using a macro for your purpose seems the only way to achieve it if dynamic allocation is off the table. But the macro could target cleaner code by providing an initializer for the structure instead of a series of member-assignment statements. You can do that in any version of standard C, but it's nicer if you can rely on designated initializers, which were introduced in C99:

    #define twi_make_fifo(name, size)\
        twi_entry_t name##_data[1<<size];\
        twi_fifo_t name = { .size_mask = ~(0xFFFF<<size), .data = name##_data };
    

    Note that there I rely there on the fact that if you provide an initializer for a structure, then any members not explicitly initialized with be initialized to 0 / NULL. Note also that you could of course use the same form directly too, without a macro.

    If it would be ok to have explicit code for each FIFO, but you just want to avoid writing each set by hand, then possibly you could write yourself a code generator to (re)generate the code for them, but I'm inclined to think that that would probably be more trouble than it's worth.