Search code examples
arrayscmacrosinitializer

C array padding


I have many data array defined in my code with the length only specified in the array initializer.

int a[] = {1, 2, 3, 4};
int b[] = {1, 2, 3, 4, 5};

For cache line coherence consideration, I want to padding them to cache line size (32). The following code can be used without scarifying the exact size information

struct {
   int payload[4];
} __attribute__((aligned(32))) a = {
   .payload = {1, 2, 3, 4}
};

struct {
   int payload[5];
} __attribute__((aligned(32))) b = {
   .payload = {1, 2, 3, 4, 5}
};

// sizeof(a.payload) == 4 * sizeof(int), sizeof(b.payload) == 5 * sizeof(int)

However, there are quite a bundle of such data, it is hard to manually rewrite them one by one. Is there a way to define a macro to handle this, like

#define ARRAY_INITIALIZER (array, initializer) ...
#define ARRAY_PAYLOAD(array) array.payload
ARRAY_INITIALIZER(a, {1, 2, 3, 4});
ARRAY_INITIALIZER(b, {1, 2, 3, 4, 5});

The most difficulty thing here is how to calculate the length of initializer here, don't get any direction for it, can anyone help here?


Solution

  • Here's one idea using variadic macros:

    #include <stdalign.h> // for "alignas" - not needed since C23
    
    #define VA_COUNT(...) (sizeof((int[]){0, __VA_ARGS__}) / sizeof(int) - 1)
    
    #define ARRAY_INITIALIZER(V, ...)                       \
        struct {                                            \
            alignas(32) int payload[VA_COUNT(__VA_ARGS__)]; \
        } V = {.payload = {__VA_ARGS__}}
    

    Note that the standard _Alignas (alignas) is used to align the array. The payload size is calculated by using VA_COUNT.

    Example use:

    #include <stdio.h>
    
    // the macro definitions from above goes here
    
    #define SIZE(x) (sizeof(x) / sizeof *(x))
    
    int main(void) {
        ARRAY_INITIALIZER(a, 1, 2, 3, 4);
    
        for (unsigned i = 0; i < SIZE(a.payload); ++i) {
            printf("%d\n", a.payload[i]);
        }
    }
    

    Output:

    1
    2
    3
    4