Boost Preprocessor Recursion - c

I'm trying to create a 'C' macro (not C++) that will define and initialize static data.
For example:
STATIC_CONST_STRUCT
(
A, a,
MEMBER_DATA(CONST_STR, a, "Hello, a")
MEMBER_DATA(CONST_STR, b, "Hello, b")
MEMBER_STRUCT
(
C, c,
MEMBER_DATA(CONST_STR, d, "Hello, d")
MEMBER_DATA(CONST_INT, e, 1)
)
);
Would cause the 'C' preprocessor to create:
static const struct A
{
CONST_STR a;
CONST_STR b;
struct C
{
CONST_STR d;
CONST_INT e;
} c;
} =
{"Hello, a", "Hello, b", {"Hello, d", 1}};
I've tried to use the Boost Preprocessor
http://www.boost.org/doc/libs/1_54_0/libs/preprocessor/doc/
but I can't quite figure out how to make this work. My macros stop expanding. I suspect the recursive nature of the problem having an arbitrarily deep nesting is why.
The solutions I read regarding getting the preprocessor to recurse either don't work, or the description of how to get recursion to work isn't clear enough to implement a working solution.
Here's what I have so far:
#define MEMBER_DATA_TAG 0
#define MEMBER_STRUCT_TAG 1
#define MEMBER_TAG(MEMBER) BOOST_PP_SEQ_ELEM(0, MEMBER)
#define MEMBER_DATA_TYPE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(1, MEMBER_DATA)
#define MEMBER_DATA_NAME(MEMBER_DATA) BOOST_PP_SEQ_ELEM(2, MEMBER_DATA)
#define MEMBER_DATA_VALUE(MEMBER_DATA) BOOST_PP_SEQ_ELEM(3, MEMBER_DATA)
#define MEMBER_STRUCT_TYPE(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(1, MEMBER_STRUCT)
#define MEMBER_STRUCT_NAME(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(2, MEMBER_STRUCT)
#define MEMBER_STRUCT_MEMBER_SEQ(MEMBER_STRUCT) BOOST_PP_SEQ_ELEM(3, MEMBER_STRUCT)
#define MEMBER_DATA(TYPE, NAME, VALUE) ((MEMBER_DATA_TAG)(TYPE)(NAME)(VALUE))
#define MEMBER_STRUCT(TYPE, NAME, MEMBER_SEQ) ((MEMBER_STRUCT_TAG)(TYPE)(NAME)(MEMBER_SEQ))
#define IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM) BOOST_PP_EQUAL(MEMBER_TAG(MEMBER_SEQ_ELEM), MEMBER_STRUCT_TAG)
#define MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) \
struct TYPE \
{ \
BOOST_PP_SEQ_FOR_EACH(MEMBER_ELEM_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ) \
} NAME
#define MEMBER_ELEM_DECLARE(_r, _data, MEMBER_SEQ_ELEM) \
BOOST_PP_IIF \
( \
IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_DECLARE \
( \
MEMBER_STRUCT_TYPE(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_NAME(MEMBER_SEQ_ELEM), \
MEMBER_STRUCT_MEMBER_SEQ(MEMBER_SEQ_ELEM) \
), \
MEMBER_DATA_DECLARE \
( \
MEMBER_DATA_TYPE(MEMBER_SEQ_ELEM), \
MEMBER_DATA_NAME(MEMBER_SEQ_ELEM), \
MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \
) \
);
#define MEMBER_DATA_DECLARE(TYPE, NAME, VALUE) TYPE NAME
#define MEMBER_VALUE_INIT(MEMBER_SEQ) \
BOOST_PP_SEQ_FOR_EACH_I(MEMBER_VALUE_INIT_DECLARE, BOOST_PP_EMPTY(), MEMBER_SEQ);
#define MEMBER_VALUE_INIT_DECLARE(_r, _data, i, MEMBER_SEQ_ELEM) \
BOOST_PP_COMMA_IF(i) \
BOOST_PP_IIF \
( \
IS_MEMBER_STRUCT(MEMBER_SEQ_ELEM), \
{MEMBER_VALUE_INIT(MEMBER_SEQ_ELEM)}, \
MEMBER_DATA_VALUE(MEMBER_SEQ_ELEM) \
)
#define STATIC_CONST_STRUCT(TYPE, NAME, MEMBER_SEQ) \
static const MEMBER_STRUCT_DECLARE(TYPE, NAME, MEMBER_SEQ) = \
{ \
MEMBER_VALUE_INIT(MEMBER_SEQ) \
}
Thanks.

It can be done without boost-preprocessor.
You don't actually need recursion. Just a loop to iterate over the macro arguments twice.
I took liberty of modifying the syntax a bit, to allow for commas in types and initializers, in case someone decides to use it with C++.
STATIC_CONST_STRUCT
(
A, a,
MEMBER_DATA(a, const char *) "Hello, a"
MEMBER_DATA(b, const char *) "Hello, b"
MEMBER_STRUCT
(
C, c,
MEMBER_DATA(d, const char *) "Hello, d"
MEMBER_DATA(e, int) 42
)
)
This expands to:
static const struct A
{
const char *a;
const char *b;
struct C
{
const char *d;
int e;
} c;
} a =
{
"Hello, a",
"Hello, b",
{
"Hello, d",
42,
},
};
Implementation:
#define STATIC_CONST_STRUCT(type_, name_, ...) \
static const struct type_ { \
END( LOOP_DECL_0 (__VA_ARGS__) ) \
} name_ = { \
END( LOOP_INIT_0 (__VA_ARGS__) ) \
};
#define MEMBER_DATA(name_, ...) )(var,name_,(__VA_ARGS__),
#define MEMBER_STRUCT(type_, name_, ...) )(open,type_ __VA_ARGS__ )(close,name_
#define IDENTITY(...) __VA_ARGS__
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x##y
#define END(...) END_(__VA_ARGS__)
#define END_(...) __VA_ARGS__##_END
#define LOOP_DECL_0() LOOP_DECL_A
#define LOOP_DECL_A(...) LOOP_DECL_BODY(__VA_ARGS__) LOOP_DECL_B
#define LOOP_DECL_B(...) LOOP_DECL_BODY(__VA_ARGS__) LOOP_DECL_A
#define LOOP_DECL_0_END
#define LOOP_DECL_A_END
#define LOOP_DECL_B_END
#define LOOP_DECL_BODY(action_, ...) CAT(LOOP_DECL_BODY_, action_)(__VA_ARGS__)
#define LOOP_DECL_BODY_var(name_, type_, ...) IDENTITY type_ name_;
#define LOOP_DECL_BODY_open(type_) struct type_ {
#define LOOP_DECL_BODY_close(name_) } name_;
#define LOOP_INIT_0() LOOP_INIT_A
#define LOOP_INIT_A(...) LOOP_INIT_BODY(__VA_ARGS__) LOOP_INIT_B
#define LOOP_INIT_B(...) LOOP_INIT_BODY(__VA_ARGS__) LOOP_INIT_A
#define LOOP_INIT_0_END
#define LOOP_INIT_A_END
#define LOOP_INIT_B_END
#define LOOP_INIT_BODY(action_, ...) CAT(LOOP_INIT_BODY_, action_)(__VA_ARGS__)
#define LOOP_INIT_BODY_var(name_, type_, ...) __VA_ARGS__,
#define LOOP_INIT_BODY_open(type_) {
#define LOOP_INIT_BODY_close(name_) },
If used with C++, IDENTITY type_ should be wrapped in std::type_identity_t<...> to allow using types such as function pointers without typedefing them. void (*)() foo; is illegal, while std::type_identity_t<void (*)()> foo; is ok.

Related

how to define a c macro that returns a function name according to the argument?

What I currently have
#define _CMPLT8 _mm_cmplt_epi8 // int8_t
#define _CMPLT32 _mm_cmplt_epi32 // int32_t
What I want (something similar to the following code)
#define _CMPLT(T) ( \
if(sizeof(T)==1) return _mm_cmplt_epi8 \
else if(sizeof(T)==4) return _mm_cmplt_epi32 \
else #error \
)
How could I this code?
If you want to return a string based on a type I'd go for generics:
#define _CMPLT(T) \
_Generic( (T), \
char: "1", \
int: "4", \
default: "0")
int main(void) {
char a;
int b;
printf("%s%s\n", _CMPLT(a), _CMPLT(b));
}
But I feel you want to call functions depending on arg type, so in that case:
#define _CMPLT(X, Y) _Generic((X), \
int8_t: _mm_cmplt_epi8(X, Y), \
int32_t: _mm_cmplt_epi32(X, Y) \
)
int main(void) {
int8_t a = 0, b = 1;
int32_t c = 2, d = 3;
printf("%d%d\n", _CMPLT(a, b), _CMPLT(c, d));
}
If you really need to use strings and sizeof, and can use compound statements, would this work for you?
#include <stdio.h>
#define _CMPLT(T) ({ \
switch(sizeof(T)) { \
case 1: "1"; \
case 4: "4"; \
}; \
"0"; \
})
int main(void) {
printf("%s%s\n",
_CMPLT(char), _CMPLT(int));
}

Conditional X-MACROs to align ENUMs and String

I have a list of enums:
typedef enum {
ENUM1,
ENUM2,
#if FLAG
ENUM3,
#endif
} enum_var_t;
And a corresponding list of strings to align:
typedef struct { char[50] name; int val; } name_val_map_t
name_val_map_t name_val_map_table[] = {
{.name="string1", .val=ENUM1},
{.name="string2", .val=ENUM2},
#if FLAG
{.name="string3", .val=ENUM3},
#endif
};
FLAG is a build flag, and is either 0, or 1.
I am trying to use X-Macros to align these according to an answer here:
#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, foo) IF_ ## cond (foo)
#define IF_0(foo)
#define IF_1(foo) foo
#define var_list \
X(ENUM1, "string1"), \
X(ENUM2, "string2"), \
IF(FLAG, X(ENUM3, "string3")), \
#define X(ENUMVAL, ...) ENUMVAL
typedef enum {
var_list
}
#undef X
#define X(ENUMVAL, NAME) {.name = NAME, .val = ENUMVAL}
name_val_map_t name_val_map_table = {
var_list
}
This leads to an error which says I'm passing more arguments to the IF macro than declared. I presume it is treating the comma inside the X(ENUM3, "string3") as an argument separator for IF.
I tried encapsulating the X() call with braces and removing the braces from IF_IMPL, but that didn't work either. If I try expand the argument list in IF() using ..., and VA_ARGS, I get expected expression errors. I'm trying to avoid using a def file as this makes my file unreadable. Some solution like I was trying would be perfect to avoid code replication, and for readability. Any pointers would be welcome, thanks!
Using variadic macros.
#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, ...) IF_ ## cond(__VA_ARGS__)
#define IF_0(foo, ...)
#define IF_1(foo, ...) foo, __VA_ARGS__
Test:
//usr/local/bin/tcc -run "$0"; exit $?
#include <stdio.h>
#define FLAG3 1
#define FLAG4 0
#define FLAG5 1
typedef struct { char *name; int val; } name_val_map_t;
#define IF(cond, foo) IF_IMPL(cond, foo)
#define IF_IMPL(cond, ...) IF_ ## cond(__VA_ARGS__)
#define IF_0(foo, ...)
#define IF_1(foo, ...) foo, __VA_ARGS__
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2") \
IF(FLAG3, X(ENUM3, "string3")) \
IF(FLAG4, X(ENUM4, "string4")) \
IF(FLAG5, X(ENUM5, "string5")) \
typedef enum {
#define X(ENUMVAL, str) ENUMVAL,
var_list
#undef X
} enum_var_t;
name_val_map_t name_val_map_table[] = {
#define X(ENUMVAL, NAME) { NAME, ENUMVAL },
var_list
#undef X
{ "sentinel value", 99 }
};
int main(void){
int x =0;
while(name_val_map_table[x].val != 99){
printf("%i, %s\n", name_val_map_table[x].val, name_val_map_table[x].name);
x++;}
return 0;
}
/* output:
0, string1
1, string2
2, string3
3, string5
*/
Another option is to manually create IF_FLAGx( X(bla, bla) ) macros for every case...
See also: macro specialization based on argument in case of MSVC bug.
This seems needlessly complicated. I would simply do this instead:
#if FLAG
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2") \
X(ENUM3, "string3")
#else
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2")
#endif
Full example:
#include <stdio.h>
#define FLAG 1
#if FLAG
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2") \
X(ENUM3, "string3")
#else
#define var_list \
X(ENUM1, "string1") \
X(ENUM2, "string2")
#endif
typedef enum
{
#define X(enum_var, str) enum_var,
var_list
#undef X
ENUM_N
} enum_var_t;
typedef struct
{
char name[50];
int val;
} name_val_map_t;
const name_val_map_t name_val_map_table[] =
{
#define X(enum_var, str) { .name = str, .val = enum_var },
var_list
#undef X
};
int main (void)
{
for(size_t i=0; i<ENUM_N; i++)
{
printf("%d %s\n", name_val_map_table[i].val, name_val_map_table[i].name);
}
}

C macro force evaluation of parameter

I am trying to force the evaluation of a macro parameter.
I tried to use the pattern in : Macro evaluation in c preprocessor
But for some reason here PP_NARG(VA_ARGS) does not expand correctly.
Do you know why the second line in main() is not compiling ?
error: pasting "RUN_CODE_FOR_EACH" and "(" does not give a valid preprocessing token
#define PP_NARG(...) (PP_NARG_(__VA_ARGS__,PP_RSEQ_N()) - \
(sizeof(#__VA_ARGS__) == 1))
#define PP_NARG_(...) PP_ARG_N(__VA_ARGS__)
#define PP_ARG_N( \
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
_61,_62,_63, N, ...) N
#define PP_RSEQ_N() \
63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9,8,7,6,5,4,3,2,1,0
#define RUN_CODE(code, x) { \
decltype(x) &&variadic_item = x; \
code; \
}
#define RUN_CODE_FOR_EACH1(code, x) RUN_CODE(code, x);
#define RUN_CODE_FOR_EACH2(code, x, ...) RUN_CODE(code, x); RUN_CODE_FOR_EACH1(code, __VA_ARGS__)
#define RUN_CODE_FOR_EACH3(code, x, ...) RUN_CODE(code, x); RUN_CODE_FOR_EACH2(code, __VA_ARGS__)
#define RUN_CODE_FOR_EACH4(code, x, ...) RUN_CODE(code, x); RUN_CODE_FOR_EACH3(code, __VA_ARGS__)
#define RUN_CODE_FOR_EACH5(code, x, ...) RUN_CODE(code, x); RUN_CODE_FOR_EACH4(code, __VA_ARGS__)
#define RUN_CODE_FOR_EACH6(code, x, ...) RUN_CODE(code, x); RUN_CODE_FOR_EACH5(code, __VA_ARGS__)
#define RUN_CODE_FOR_EACH7(code, x, ...) RUN_CODE(code, x); RUN_CODE_FOR_EACH6(code, __VA_ARGS__)
#define RUN_CODE_FOR_EACH8(code, x, ...) RUN_CODE(code, x); RUN_CODE_FOR_EACH7(code, __VA_ARGS__)
#define RUN_CODE_FOR_EACH__(code, size, ...) RUN_CODE_FOR_EACH##size(code, __VA_ARGS__)
#define RUN_CODE_FOR_EACH_(code, size, ...) RUN_CODE_FOR_EACH__(code, size, __VA_ARGS__)
#define RUN_CODE_FOR_EACH(code, ...) RUN_CODE_FOR_EACH_(code, PP_NARG(__VA_ARGS__), __VA_ARGS__)
void print(int i){std::cout << "int: " << i << '\n';}
int print(double d){std::cout << "double: " << d << '\n';return 2;}
int main() {
RUN_CODE_FOR_EACH_(print(variadic_item), 4, 1, 2., 3., 4); // Working
RUN_CODE_FOR_EACH(print(variadic_item), 1, 2., 3., 4); // Compilation error
std::cout << "size=" << PP_NARG(1, 2., 3., 4) << '\n'; // show size=4
return 0;
}
Thank you
PP_NARG does not make sense, as you're using compile-time constructs at preprocessor-time. You will not get a valid preprocessor-time argument count. You need to count the arguments without resorting to things like sizeof.
Here's an example on how that could be done from my vrm_pp library. First, I define the interface macros for argument counting:
#define VRM_PP_IMPL_N_ARG(...) VRM_PP_IMPL_NSEQ(__VA_ARGS__)
#define VRM_PP_IMPL_ARGCOUNT(...) \
VRM_PP_IMPL_N_ARG(__VA_ARGS__, VRM_PP_IMPL_RSEQ())
#define VRM_PP_ARGCOUNT(...) VRM_PP_IMPL_ARGCOUNT(__VA_ARGS__)
I then use a generator script to generate the count sequences.
VRM_PP_IMPL_RSEQ is a reverse-counting sequence: 10, 9, 8, 7, 6 ...
VRM_PP_IMPL_NSEQ is a macro that takes N arguments (where N is the maximum supported number of arguments) and returns the N-th argument.
You can find a complete explanation of this solution on the "C++ preprocessor __VA_ARGS__ number of arguments" question.

A group of variadic macros

I would like to have a group of variable number of arguments passed into a macro. I have following macros which is incorrect:
#define M_NARGS(...) M_NARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define M_NARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
#define M_CONC(A, B) M_CONC_(A, B)
#define M_CONC_(A, B) A##B
#define M_ID(...) __VA_ARGS__
#define M_LEFT(L, R) L
#define M_RIGHT(L, R) R
#define M_FOR_EACH(ACTN, ...) M_CONC(M_FOR_EACH_, M_NARGS(__VA_ARGS__)) (ACTN, __VA_ARGS__)
#define M_FOR_EACH_0(ACTN, E) E
#define M_FOR_EACH_1(ACTN, E) ACTN(E)
#define M_FOR_EACH_2(ACTN, E, ...) ACTN(E) M_FOR_EACH_1(ACTN, __VA_ARGS__)
#define M_FOR_EACH_3(ACTN, E, ...) ACTN(E) M_FOR_EACH_2(ACTN, __VA_ARGS__)
#define M_FOR_EACH_4(ACTN, E, ...) ACTN(E) M_FOR_EACH_3(ACTN, __VA_ARGS__)
#define M_FOR_EACH_5(ACTN, E, ...) ACTN(E) M_FOR_EACH_4(ACTN, __VA_ARGS__)
#define FRUITS (apple, banana, cherry)
#define ANIMALS (dog, monkey)
#define ZOO_BLOCK(NAME, FRTS, ANMLS) struct NAME##Block { \
M_FOR_EACH(DEFINE_FRUITS, FRTS) \ // Wrong, see my question below
M_FOR_EACH(DEFINE_ANIMAL, ANMLS) \ // Wrong
}
#define DEFINE_FRUITS(F) Fruit F;
#define DEFINE_ANIMALS(F) Animal F;
ZOO_BLOCK(MyZoo, FRUITS, ANIMALS);
By M_FOR_EACH(DEFINE_FRUITS, FRTS), I would like to do M_FOR_EACH(DEFINE_FRUITS, __VA_ARGS__) actually and __VA_ARGS__ are all from FRUITS (i.e. apple, banana, cherry). How can I change my macros to do this?
I'm not sure whether this is what you are looking for, but the parenthesised fruit and animal groups are not resolved. You can "flatten" them with your M_IDmacro, e.g.:
#define M_ID(...) __VA_ARGS__
#define FRUITS M_ID(apple, banana, cherry)
#define ANIMALS M_ID(dog, monkey)
#define ZOO_BLOCK(NAME, FRTS, ANMLS) struct NAME##Block { \
M_FOR_EACH(DEFINE_FRUITS, FRTS) \
M_FOR_EACH(DEFINE_ANIMALS, ANMLS) \
}
#define DEFINE_FRUITS(F) Fruit F;
#define DEFINE_ANIMALS(F) Animal F;
ZOO_BLOCK(MyZoo, FRUITS, ANIMALS);
This, together with correcting a minor typo in DEFINE_ANIMAL/S yields:
struct MyZooBlock {
Fruit apple;
Fruit banana;
Fruit cherry;
Animal dog;
Animal monkey;
};
If you want to generate structs based on lists I would use higher order macros.
This does not require you to have another macro that actually does the loop resolution.
#define FRUITS(V) \
V(apple) \
V(banana) \
V(cherry)
#define ANIMALS(V) \
V(dog) \
V(monkey)
#define VISIT_ANI_STRUCT(A) \
Animal A;
#define VISIT_FRU_STRUCT(F) \
Fruit F;
#define ZOO_BLOCK(NAME, GEN_ANI,GEN_FRU) \
struct NAME ## Block { \
ANIMALS(GEN_ANI) \
FRUITS(GEN_FRU) \
}
ZOO_BLOCK(Zoo, VISIT_ANI_STRUCT, VISIT_FRU_STRUCT);
Will result in:
struct ZooBlock { Animal dog; Animal monkey; Fruit apple; Fruit banana; Fruit cherry; };
Or if you need the other way round
#define ZOO_BLOCK(NAME, A, F) \
struct NAME ## Block { \
A(VISIT_ANI_STRUCT) \
F(VISIT_FRU_STRUCT) \
}
ZOO_BLOCK(Zoo, VISIT_ANI_STRUCT, VISIT_FRU_STRUCT);

Variable arguements in macro using ellipsis

I want to define a macro accepting either 1 or 2 parameters. Both the parameters should be different type. How to use ellipsis and read the arguments passed?
Below is the sample:
void test(char *var2)
{
printf("%s\n",var2);
}
#define PRINT_STRING(...) ( if (!var1) test(var2) )
int main(int argc, _TCHAR argv[]) {
PRINT_STRING(TRUE);
PRINT_STRING(FALSE,"Hello, World!");
return 0;
}
This is known as a Variadic macro.
If your compiler supports __VA_ARGS__, you can do it like this:
#include <stdio.h>
#define NUM_ARGS__(X, \
N64,N63,N62,N61,N60, \
N59,N58,N57,N56,N55,N54,N53,N52,N51,N50, \
N49,N48,N47,N46,N45,N44,N43,N42,N41,N40, \
N39,N38,N37,N36,N35,N34,N33,N32,N31,N30, \
N29,N28,N27,N26,N25,N24,N23,N22,N21,N20, \
N19,N18,N17,N16,N15,N14,N13,N12,N11,N10, \
N09,N08,N07,N06,N05,N04,N03,N02,N01, N, ...) N
#define NUM_ARGS(...) \
NUM_ARGS__(0, __VA_ARGS__, \
64,63,62,61,60, \
59,58,57,56,55,54,53,52,51,50, \
49,48,47,46,45,44,43,42,41,40, \
39,38,37,36,35,34,33,32,31,30, \
29,28,27,26,25,24,23,22,21,20, \
19,18,17,16,15,14,13,12,11,10, \
9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
#define PRINT_STRING_1(var) \
{ if (!(var)) {} }
#define PRINT_STRING_2(var, ...) \
{ if (!(var)) test(__VA_ARGS__); }
#define PRINT_STRINGN__(N, ...) \
PRINT_STRING_##N(__VA_ARGS__)
#define PRINT_STRINGN(N, ...) \
PRINT_STRINGN__(N, __VA_ARGS__)
#define PRINT_STRING(...) \
PRINT_STRINGN(NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
void test(char* var2)
{
printf("%s\n", var2);
}
int main(void)
{
PRINT_STRING(1);
PRINT_STRING(0, "Hello, World!");
PRINT_STRING(1, "You can't see me!");
return 0;
}
Output:
Hello, World!
To do something like that you'd have to implement a series of macros, something like this
#include <stdbool.h>
#define PRINT_STRING0(X, Y) do { if (X && Y) test(Y); } while(false)
#define PRINT_STRING1(X, Y, ...) PRINT_STRING0(X, Y)
#define PRINT_STRING(...) PRINT_STRING1(__VA_ARGS__, 0, 0)
The last of them (user interface) adds a second or third argument of 0. PRINT_STRING1 then ignores all arguments that are more than 2. And PRINT_STRING0 then does the work.
Some more remarks:
be careful that a macro like you want to program it here can be place syntactically just as any other statement. In the example here the do { } while(false) does that trick
since C99 has Boolean type and constants, these are _Bool or bool and false and true
Don't use a macro to do that, use a variadic function!
void print_string( bool should_print, ... )
{
if( should_print )
{
va_list argp;
va_start( argp, should_print);
char *string = va_arg(argp, char *);
if( string) printf("%s", string );
va_end( argp );
}
}
But be very careful when using these sorts of things, because va_arg doesn't check if you really have a 2nd argument.
Also, to use a macro that accepts one or 2 arguments, use the GCC trick (at the very bottom of this page):
#define PRINT_STRING( should , args... ) print_string( should , ##args )
(note the spaces between the commas)

Resources