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?
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