I've defined a few macros that make it simpler to define an array of structures, but I can't find a way to use them without generating errors. Here are the macros (and a few example structures to demonstrate why the macros might be used (the actual structures I'm populating are a little more complex)):
struct string_holder {
const char *string;
};
struct string_array_holder {
struct string_holder *holders;
};
#define DEFINE_STRING_ARRAY_HOLDER(name, values) \
static struct string_holder name##__array[] = values; \
static struct string_array_holder name = { name##__array }
#define WRAP_STRING(string) { string }
It works just fine when you use it to declare an array with one item:
DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, {
WRAP_STRING("my string")
});
But when I use multiple items:
DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, {
WRAP_STRING("hello"),
WRAP_STRING("world")
});
I get this error:
error: too many arguments provided to function-like macro invocation
So it's interpreting the comma in the braces as an argument separator. I follow the advice from this question and put parentheses around the problematic argument:
DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, ({
WRAP_STRING("hello"),
WRAP_STRING("world")
}));
Now when I try to compile it, it interprets ({ ... })
as a statement expression and complains:
warning: use of GNU statement expression extension
(a bunch of syntax errors resulting from its interpretation as a statement expression)
error: statement expression not allowed at file scope
How can I either:
Dmitri is right, variadic macros are the way to go.
I put some example code I use to test if given key is member of a list of values:
#define _IN(KEY, ...) \
({ \
typedef __typeof(KEY) _t; \
const _t _key = (KEY); \
const _t _values[] = { __VA_ARGS__ }; \
_Bool _r = 0; \
unsigned int _i; \
for (_i = 0; _i < sizeof(_values) / sizeof(_values[0]); ++_i) { \
if (_key == _values[_i]) { \
_r = 1; \
break; \
} \
} \
_r; \
})
Mind the usage of __VA_ARGS__
.
Update:
A crude solution if you don't like __VA_ARGS__
at arbitrary places would be an "unwrapper" macro:
#define UNWRAP(...) __VA_ARGS__
You could use it like a prefix-operator. ;-)
#include <stdio.h>
/* "unwrapper": */
#define UNWRAP(...) __VA_ARGS__
/* your macros: */
#define WRAP(NAME, ELEMS) static const char *NAME[] = { UNWRAP ELEMS }
int main(void) {
WRAP(some_test, ("a", "b", "c"));
printf("The second elem in some_test is: '%s'\n", some_test[1]);
return 0;
}
Yes, use __VA_ARGS__
, but Kay's solution is much too complicated. Just doing:
#define DEFINE_STRING_ARRAY_HOLDER(name, ...) \
static struct string_holder name##_array[] = __VA_ARGS__; \
static struct string_array_holder name = { name##_array }
suffices. You may then just use this macro as you intended with:
DEFINE_STRING_ARRAY_HOLDER(my_string_array_holder, {
WRAP_STRING("hello"),
WRAP_STRING("world")
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With