I am trying to write a macro which counts the number of specific elements in a sequence. E.g. for the sequence (A)(B)(A) I want to get the count 2 for A.
Now taking the approach from https://stackoverflow.com/a/12540675/2525536 I end up with this code:
#define CAT(x, ...) CAT1(x, __VA_ARGS__)
#define CAT1(x, ...) CAT2(x, __VA_ARGS__)
#define CAT2(x, ...) x ## __VA_ARGS__
#define EXPAND(...) __VA_ARGS__
#define EAT(...)
#define DEFER(...) __VA_ARGS__ EAT()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EAT)()
#define SIZE(seq) CAT(SIZE_, SIZE_0 seq)
#define SIZE_0(...) SIZE_1
#define SIZE_1(...) SIZE_2
#define SIZE_2(...) SIZE_3
#define SIZE_3(...) SIZE_4
#define SIZE_SIZE_0 0
#define SIZE_SIZE_1 1
#define SIZE_SIZE_2 2
#define SIZE_SIZE_3 3
#define SIZE_SIZE_4 4
#define GET_FIRST(x) GET_FIRST2(GET_FIRST1 x)
#define GET_FIRST1(x) x, EAT()
#define GET_FIRST2(x) GET_FIRST3(x)
#define GET_FIRST3(x, ...) x
#define POP_FIRST(x) EAT x
#define EVAL(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL3(EVAL3(__VA_ARGS__))
#define EVAL3(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) __VA_ARGS__
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define CHECK_PROBE(x) x, 1,
#define NOT(x) CHECK(CAT(NOT_, x))
#define NOT_0 ~, 1,
#define COMPL(b) CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BOOL(x) COMPL(NOT(x))
#define IIF(c) CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF(c) IIF(BOOL(c))
#define WHEN(c) IF(c)(EXPAND, EAT)
#define INC(x) CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define DEC(x) CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define COUNT_IF(tpl, data, x) COUNT_IF1(0, SIZE(x), 0, tpl, data, x)
#define COUNT_IF1(i, n, count, tpl, data, x) \
IF(n) ( \
OBSTRUCT(CAT) ( \
COUNT_IF3_, \
tpl(i, data, GET_FIRST(x)) \
) ( \
OBSTRUCT(COUNT_IF2)() \
(INC(i), DEC(n), count, tpl, data, POP_FIRST(x)) /* call recursive */ \
) \
, count \
)
#define COUNT_IF2() COUNT_IF1
#define COUNT_IF3_0 EXPAND
#define COUNT_IF3_1 INC
#define A_EQUAL_A(...) 1
#define A_EQUAL_B(...) 0
#define COUNT_A(i, data, x) CAT(A_EQUAL_, x)(i)
EVAL(COUNT_IF(COUNT_A, ~, (A)))
EVAL(COUNT_IF(COUNT_A, ~, (B)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(B)))
EVAL(COUNT_IF(COUNT_A, ~, (B)(A)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(A)))
EVAL(COUNT_IF(COUNT_A, ~, (B)(B)))
EVAL(COUNT_IF(COUNT_A, ~, (A)(B)(A)))
This works already quite well for the first 4 examples but ends up with wrong macro name expandation for the others (where INC or EXPAND needs to be expanded more than once).
The reason for the is probably because macros are marked blue in C, which is why this works https://stackoverflow.com/a/11640759/2525536.
But I cannot find a workaround for this.
Anyone an idea?
As I already received some comments about using the C preprocessor for this task is not an appropiate way of handling this issue I still intent to go this way not only to minimize code dependencies but also to make the best out of what C offers in my code (which may not be obvious here).
Having this said I found out why the macro was not expanding correctly and also a way to make the preprocessor do this task correctly.
The issue was that the macro generated a construct like INC(EXPAND(INC(0))) from outside (first element) to inside (last element). The preprocessor tried to solve this while always only knowing all values until the current level/element. This turned into something like INC(COUNT_IF1(...)) on which point the preprocessor started to substitute INC for example.
The correct way of handling this was to make the preprocessor extend the macro from inside to outside.
Simplifying the code a little bit gives this solution:
#define CAT(x, ...) CAT1(x, __VA_ARGS__)
#define CAT1(x, ...) CAT2(x, __VA_ARGS__)
#define CAT2(x, ...) x ## __VA_ARGS__
#define EXPAND(...) __VA_ARGS__
#define EAT(...)
#define DEFER(...) __VA_ARGS__ EAT()
#define OBSTRUCT(...) __VA_ARGS__ DEFER(EAT)()
#define SIZE(seq) CAT(SIZE_, SIZE_0 seq)
#define SIZE_0(...) SIZE_1
#define SIZE_1(...) SIZE_2
#define SIZE_2(...) SIZE_3
#define SIZE_3(...) SIZE_4
#define SIZE_SIZE_0 0
#define SIZE_SIZE_1 1
#define SIZE_SIZE_2 2
#define SIZE_SIZE_3 3
#define SIZE_SIZE_4 4
#define GET_FIRST(x) GET_FIRST2(GET_FIRST1 x)
#define GET_FIRST1(x) x, EAT()
#define GET_FIRST2(x) GET_FIRST3(x)
#define GET_FIRST3(x, ...) x
#define POP_FIRST(x) EAT x
#define EVAL(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL3(EVAL3(__VA_ARGS__))
#define EVAL3(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) __VA_ARGS__
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define CHECK_PROBE(x) x, 1,
#define NOT(x) CHECK(CAT(NOT_, x))
#define NOT_0 ~, 1,
#define COMPL(b) CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BOOL(x) COMPL(NOT(x))
#define IIF(c) CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF(c) IIF(BOOL(c))
#define WHEN(c) IF(c)(EXPAND, EAT)
#define INC(x) CAT(INC_, x)
#define INC_0 1
#define INC_1 2
#define INC_2 3
#define INC_3 4
#define INC_4 5
#define DEC(x) CAT(DEC_, x)
#define DEC_0 0
#define DEC_1 0
#define DEC_2 1
#define DEC_3 2
#define DEC_4 3
#define DEC_5 4
#define IS_PAREN(x) CHECK(IS_PARENT1 x)
#define IS_PARENT1(...) CHECK_PROBE(~)
#define IS_COMPARABLE(x) IS_PAREN(CAT(COMPARE_, x)(()))
#define BITAND(lhs, rhs) CAT(CAT(CAT(BITAND_, lhs), _), rhs)
#define BITAND_0_0 0
#define BITAND_0_1 0
#define BITAND_1_0 0
#define BITAND_1_1 1
#define NOT_EQUAL(lhs, rhs) \
IIF(BITAND(IS_COMPARABLE(lhs), IS_COMPARABLE(rhs)))( \
NOT_EQUAL_HELPER, \
1 NULL \
)(lhs, rhs)
#define NOT_EQUAL_HELPER(lhs, rhs) IS_PAREN( \
CAT(COMPARE_, lhs)(CAT(COMPARE_, rhs))(()) \
)
#define EQUAL(lhs, rhs) COMPL(NOT_EQUAL(lhs, rhs))
#define COUNT_IF(match, x) COUNT_IF1(SIZE(x), match, 0, x)
#define COUNT_IF1(n, match, count, x) \
IF(n) ( \
OBSTRUCT(COUNT_IF2)()( \
DEC(n), \
match, \
IF(match(GET_FIRST(x)))(INC, EXPAND)(count), POP_FIRST(x) \
) /* call recursive */ \
, count \
)
#define COUNT_IF2() COUNT_IF1
#define COMPARE_A(x) x
#define EQUAL_A(x) EQUAL(x, A)
EVAL(COUNT_IF(EQUAL_A, (A)))
EVAL(COUNT_IF(EQUAL_A, (B)))
EVAL(COUNT_IF(EQUAL_A, (A)(B)))
EVAL(COUNT_IF(EQUAL_A, (B)(A)))
EVAL(COUNT_IF(EQUAL_A, (A)(A)))
EVAL(COUNT_IF(EQUAL_A, (B)(B)))
EVAL(COUNT_IF(EQUAL_A, (A)(B)(A)(A)))
P.S.: An 11 lines macro still seems simple enough to me to handle in terms of complexity and maintainability.
Related
A #define's replacement list containing no spaces can be mapped to integers (IDs):
#define ID_double 1
#define ID_float 2
#define ID_long_double 3
#define ID_(x) ID_##x
#define ID(x) ID_(x)
#define T double
T v;
int x = ID(T); /* 1 */
Now consider:
#define T long double
The code above won't compile:
<source>:3:25: error: 'ID_long' undeclared here (not in a function)
Question: is there a way to support spaces?
For example (somehow):
#define REPLACE_SPACES_TO_UNDERSCORES(x) ??
#define ID(x) ID_(REPLACE_SPACES_TO_UNDERSCORES(x))
#define T long double
T v;
int x = ID(T); /* 3 */
The same idea I had in Replace spaces with underscores in a macro? can also be used here, and the dictionary will be much more realistical in size. In the following code on the end, ID(T) is replaced by 3.
// dictionary
#define WORD_long long,
#define WORD_double double,
// ---------------------------------------------
// the classics
#define COMMA(...) ,
#define FIRST(a, ...) a
// apply function f for each argument recursively with tail
#define FOREACHTAIL_1(f,a) f(a,)
#define FOREACHTAIL_2(f,a,...) f(a,FOREACHTAIL_1(f,__VA_ARGS__))
#define FOREACHTAIL_3(f,a,...) f(a,FOREACHTAIL_2(f,__VA_ARGS__))
#define FOREACHTAIL_4(f,a,...) f(a,FOREACHTAIL_3(f,__VA_ARGS__))
#define FOREACHTAIL_N(_4,_3,_2,_1,N,...) \
FOREACHTAIL_##N
#define FOREACHTAIL(f,...) \
FOREACHTAIL_N(__VA_ARGS__,4,3,2,1)(f,__VA_ARGS__)
// if there are two arguments, expand to true. Otherwise false.
#define IFTWO_N(_0,_1,N,...) N
#define IFTWO(true, false, ...) IFTWO_N(__VA_ARGS__, true, false)
// If empty, expand to true, otherwise false.
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define IFEMPTY(true, false, ...) IFTWO(true, false, COMMA __VA_ARGS__ ())
// Join arguments with `_`.
#define JOIN_U(a, b) a##_##b
#define JOIN_TWO_IN(a,b) IFEMPTY(FIRST, JOIN_U, b)(a, b)
#define JOIN_TWO(a,b) JOIN_TWO_IN(a,b)
#define JOIN(...) FOREACHTAIL(JOIN_TWO, __VA_ARGS__)
// Append WORD_ to each argument and join arguments with spaces.
#define WORD_ /* the last one expands to empty */
#define WORDS_TWO(a, b) WORD_##a b
#define WORDS(...) FOREACHTAIL(WORDS_TWO, __VA_ARGS__)
#define REPLACE_SPACES_TO_UNDERSCORES(a) JOIN(WORDS(WORDS(WORDS(WORDS(WORDS(a))))))
// --------------------------------------------
#define ID_double 1
#define ID_float 2
#define ID_long_double 3
#define ID_IN2(x) ID_##x
#define ID_IN(x) ID_IN2(x)
#define ID(x) ID_IN(REPLACE_SPACES_TO_UNDERSCORES(x))
int main() {
#define T long double
T v;
int x = ID(T); /* 3 */
}
I have the following defines:
#define M(x) ( ((uint64_t) 1) << (x) )
#define Mx M(0)
#define My M(1)
#define Mz M(2)
Quite often I need to rearrange the order of Mx, My, Mz, for example:
#define My M(0)
#define Mz M(1)
#define Mx M(2)
How would I make this more generic in a sense of not having to correct M(0/1/2) every time, but just shuffle the lines?
#define POS ...
#define My M(POS)
#define Mz M(POS)
#define Mx M(POS)
You could use an extra macro in between that will select an appropriate argument from the permutation. The permutation would be a macro itself that can be undefined and redefined.
#define NTH0(a0,a1,a2) a0
#define NTH1(a0,a1,a2) a1
#define NTH2(a0,a1,a2) a2
#define NTH(n, perm) NTH ## n (perm)
#define Mx M(NTH(0, PERM))
#define My M(NTH(1, PERM))
#define Mz M(NTH(2, PERM))
#define PERM 1,2,3
Mx
My
Mz
#undef PERM
#define PERM 3,2,1
Mx
My
Mz
When compiled with gcc -E it expands to:
M(1)
M(2)
M(3)
M(3)
M(2)
M(1)
The best solution might be to solve this with version control or #ifdef switches rather than function-like macros. Or perhaps generate the C source through a script.
Otherwise, the standard pre-processor way to list stuff while avoiding code repetition is "X macros", where you only need to change the values in a single place (called M_LIST in this example):
#include <stdio.h>
#include <inttypes.h>
#define M_LIST(X) \
X(x,0) \
X(y,1) \
X(z,2) \
#define M_enum(symbol,val) M##symbol##_bit = val,
enum { M_LIST(M_enum) };
#define M(symbol) ( 1ull << (M##symbol##_bit) )
int main (void)
{
printf("%.16"PRIx64"\n", M(x));
printf("%.16"PRIx64"\n", M(y));
printf("%.16"PRIx64"\n", M(z));
}
Here a temporary enum is created, which will expand to:
enum { Mx_bit = 0, My_bit = 1, Mz_bit = 2, }. These constants aren't used directly by your program, but only through the macro M.
As I was searching for a way to do reflection in C, I found this answer https://stackoverflow.com/a/31908340/6784916.
In his answer, he refers to the metaresc library and he shows an example how to use it:
TYPEDEF_STRUCT (point_t,
double x,
double y
);
int main (int argc, char * argv[])
{
point_t point = {
.x = M_PI,
.y = M_E,
};
...
}
TYPEDEF_STRUCT is defined on line 237 of https://github.com/alexanderchuranov/Metaresc/blob/master/src/metaresc.h
I tried extracting the source of the macro but I'm not sure if I missed something because it's so complex.
#define TYPEDEF_STRUCT(...) P00_TYPEDEF (STRUCT, __VA_ARGS__)
#ifndef MR_MODE
#define MR_MODE_UNDEFINED
#define MR_MODE PROTO
#endif
#include <mr_protos.h>
#ifdef MR_MODE_UNDEFINED
#undef MR_MODE_UNDEFINED
#undef MR_MODE
#endif
#define MR_IS_MR_MODE_EQ_MR_MODE 0
#define P00_TYPEDEF(...) \
MR_IF_ELSE (MR_PASTE2 (MR_IS_MR_MODE_EQ_, MR_MODE)) \
(P00_TYPEDEF_MODE (MR_MODE, __VA_ARGS__)) \
(P00_TYPEDEF_MODE (PROTO, __VA_ARGS__) P00_TYPEDEF_MODE (DESC, __VA_ARGS__))
#define MR_IGNORE(...)
#define MR_IDENT(...) __VA_ARGS__
#define MR_IF_ELSE_CASE_0(...) __VA_ARGS__ MR_IGNORE
#define MR_IF_ELSE_CASE_1(...) MR_IDENT
#define MR_IF_ELSE(...) MR_PASTE2 (MR_IF_ELSE_CASE_, MR_IS_EQ_0 (__VA_ARGS__))
#define MR_PASTE2(...) MR_PASTE2_ (__VA_ARGS__)
#define MR_PASTE2_(_0, _1) _0 ## _1
#define MR_IS_0_EQ_0 ,
#define MR_IS_EQ_0_CASE_011 ,
#define MR_GET_SECOND(_0, ...) __VA_ARGS__
#define MR_IS_EQ_0(...) MR_IS_EQ_0_ (__VA_ARGS__) /* evaluate arguments */
#define MR_IS_EQ_0_(...) MR_IS_EQ_0__ ((__VA_ARGS__), (MR_PASTE2 (MR_IS_0_EQ_, __VA_ARGS__)))
#define MR_IS_EQ_0__(ARGS, ARGS_EQ_0) \
MR_HAS_COMMA (MR_PASTE4 (MR_IS_EQ_0_CASE_, \
/* test if there is just one argument, eventually a zero */ \
MR_HAS_COMMA ARGS, \
/* test if MR_IS_0_EQ_ together with the argument adds a comma */ \
MR_HAS_COMMA ARGS_EQ_0, \
/* test that there is nothing after comma */ \
MR_IS_EMPTY (MR_GET_SECOND ARGS_EQ_0)))
#define P00_TYPEDEF_MODE(P00_MODE, P00_TYPE, ...) \
P00_TYPEDEF_MODE_ (P00_MODE, P00_TYPE, \
ATTRIBUTES (P00_GET_ATTRIBUTES (__VA_ARGS__)), \
P00_GET_NON_ATTRIBUTES (__VA_ARGS__))
#define P00_TYPEDEF_MODE_(...) P00_TYPEDEF_MODE__ (__VA_ARGS__)
#define P00_TYPEDEF_MODE__(P00_MODE, P00_TYPE, ATTR_META_RES, ...) \
#define P00_GET_ATTRIBUTES(...) MR_FOREACH (P00_EXTRACT_ATTRIBUTES, __VA_ARGS__)
#define P00_GET_NON_ATTRIBUTES(...) MR_FOREACH (P00_EXTRACT_NON_ATTRIBUTES, __VA_ARGS__)
#define MR_FOREACH(X, ...) MR_PASTE2 (MR_FOREACH, MR_NARG (__VA_ARGS__)) (X, __VA_ARGS__)
#define MR_FOR(NAME, N, OP, FUNC, ...) MR_PASTE2 (MR_FOR, N) (NAME, OP, FUNC, __VA_ARGS__)
#define P00_TYPEDEF_ATTR_STRUCT TYPEDEF_ATTR
#define P00_TYPEDEF_ATTR_UNION TYPEDEF_ATTR
#define P00_TYPEDEF_ATTR_ENUM TYPEDEF_ATTR
#define P00_TYPEDEF_ATTR_CHAR_ARRAY(P00_MODE, P00_TYPE, ATTR_META_RES, P00_TYPE_NAME, SIZE, ...) MR_PASTE2 (MR_TYPEDEF_CHAR_ARRAY_, P00_MODE) (P00_TYPE_NAME, SIZE, MR_PASTE2 (P00_REMOVE_, ATTR_META_RES), __VA_ARGS__)
#define P00_TYPEDEF_ATTR_FUNC(P00_MODE, P00_TYPE, ATTR_META_RES, RET_TYPE, P00_TYPE_NAME, ARGS, ...) MR_PASTE2 (MR_TYPEDEF_FUNC_, P00_MODE) (RET_TYPE, P00_TYPE_NAME, ARGS, MR_PASTE2 (P00_REMOVE_, ATTR_META_RES), __VA_ARGS__)
#define P00_UNFOLD(PREFIX, P00_TYPE, P00_MODE, ...) MR_PASTE4 (PREFIX, P00_TYPE, _, P00_MODE) (__VA_ARGS__)
#define TYPEDEF_ATTR(P00_MODE, P00_TYPE, ATTR_META_RES, P00_TYPE_NAME, ...) \
P00_UNFOLD (MR_TYPEDEF_, P00_TYPE, P00_MODE, P00_TYPE_NAME, MR_PASTE2 (P00_GET_FIRST_, ATTR_META_RES)) \
MR_FOR ((P00_MODE, P00_TYPE_NAME), MR_NARG (__VA_ARGS__), MR_SER, MR_PASTE3 (P00_, P00_TYPE, _HANDLER), __VA_ARGS__) \
P00_UNFOLD (MR_END_, P00_TYPE, P00_MODE, P00_TYPE_NAME, MR_PASTE2 (P00_GET_OTHER_, ATTR_META_RES))
# define P00_IS_ATTRIBUTES_EQ_ATTRIBUTES(...) 0 /* help macro for ATTRIBUTES test IF clause */
#define P00_REMOVE_ATTRIBUTES(...) __VA_ARGS__
#define P00_GET_FIRST_ATTRIBUTES(FIRST, ...) FIRST /* extract typedef attributes */
#define P00_GET_OTHER_ATTRIBUTES(FIRST, ...) __VA_ARGS__ /* extract typedef meta information */
All I want to know is how can a macro call such as
TYPEDEF_STRUCT (point_t,
double x,
double y
);
expand to that
typedef struct point_t {
double x;
double y;
} point_t;
I'm not sure why do you want to decouple headers from the rest of the library. Probably first 700 lines of metaresc.h are used in TYPEDEF_STRUCT, so you will need most of this file. Even though it will not help you, just because result of the macro is typedef + meta-data required for serialization. Serialization functions are implemented in the library, so there is no sense to decouple meta-data generation from the code that uses this meta-data.
You could run example through preprocessor and evaluate outcome. This will give you and idea what do I mean as meta-data.
If you are really interested in understanding of TYPEDEF_STRUCT macro implementation details, then get ready for 100+ layers of nested macros. As a first exercises you could start here https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/ and continue with other macro tricks from https://p99.gforge.inria.fr/
I'd like to know how to apply a unary function (or another macro) to variadic arguments of a macro, like
int f(int a);
#define apply(args...) <the magic>
apply(a, b, c)
which unrolls
f(a)
f(b)
f(c)
Note that the number of arguments is unknown.
The code below is working for what you've asked for with up to 1024 arguments and without using additional stuff like boost. It defines an EVAL(...) and also a MAP(m, first, ...) macro to do recursion and to use for each iteration the macro m with the next parameter first.
With the use of that, your apply(...) looks like: #define apply(...) EVAL(MAP(apply_, __VA_ARGS__)).
It is mostly copied from C Pre-Processor Magic. It is also great explained there. You can also download these helper macros like EVAL(...) at this git repository, there are also a lot of explanation in the actual code. It is variadic so it takes the number of arguments you want.
But I changed the FIRST and the SECOND macro as it uses a Gnu extension like it is in the source I've copied it from. This is said in the comments below by #HWalters:
Specifically, 6.10.3p4: "Otherwise [the identifier-list ends in a ...] there shall be more arguments in the invocation than there are parameters in the macro definition (excluding the ...)".
Main function part:
int main()
{
int a, b, c;
apply(a, b, c) /* Expands to: f(a); f(b); f(c); */
return 0;
}
Macro definitions:
#define FIRST_(a, ...) a
#define SECOND_(a, b, ...) b
#define FIRST(...) FIRST_(__VA_ARGS__,)
#define SECOND(...) SECOND_(__VA_ARGS__,)
#define EMPTY()
#define EVAL(...) EVAL1024(__VA_ARGS__)
#define EVAL1024(...) EVAL512(EVAL512(__VA_ARGS__))
#define EVAL512(...) EVAL256(EVAL256(__VA_ARGS__))
#define EVAL256(...) EVAL128(EVAL128(__VA_ARGS__))
#define EVAL128(...) EVAL64(EVAL64(__VA_ARGS__))
#define EVAL64(...) EVAL32(EVAL32(__VA_ARGS__))
#define EVAL32(...) EVAL16(EVAL16(__VA_ARGS__))
#define EVAL16(...) EVAL8(EVAL8(__VA_ARGS__))
#define EVAL8(...) EVAL4(EVAL4(__VA_ARGS__))
#define EVAL4(...) EVAL2(EVAL2(__VA_ARGS__))
#define EVAL2(...) EVAL1(EVAL1(__VA_ARGS__))
#define EVAL1(...) __VA_ARGS__
#define DEFER1(m) m EMPTY()
#define DEFER2(m) m EMPTY EMPTY()()
#define IS_PROBE(...) SECOND(__VA_ARGS__, 0)
#define PROBE() ~, 1
#define CAT(a,b) a ## b
#define NOT(x) IS_PROBE(CAT(_NOT_, x))
#define _NOT_0 PROBE()
#define BOOL(x) NOT(NOT(x))
#define IF_ELSE(condition) _IF_ELSE(BOOL(condition))
#define _IF_ELSE(condition) CAT(_IF_, condition)
#define _IF_1(...) __VA_ARGS__ _IF_1_ELSE
#define _IF_0(...) _IF_0_ELSE
#define _IF_1_ELSE(...)
#define _IF_0_ELSE(...) __VA_ARGS__
#define HAS_ARGS(...) BOOL(FIRST(_END_OF_ARGUMENTS_ __VA_ARGS__)())
#define _END_OF_ARGUMENTS_() 0
#define MAP(m, first, ...) \
m(first) \
IF_ELSE(HAS_ARGS(__VA_ARGS__))( \
DEFER2(_MAP)()(m, __VA_ARGS__) \
)( \
/* Do nothing, just terminate */ \
)
#define _MAP() MAP
#define apply_(x) f(x);
#define apply(...) EVAL(MAP(apply_, __VA_ARGS__))
To test macro expansion it is useful to use gcc with the command line argument -E:
$ gcc -E srcFile.c
because your're getting concrete error messages and understand what's going on.
Everything is possible in C if you throw enough ugly macros at it. For example, you can have an ugly function-like macro:
#include <stdio.h>
int f (int a)
{
printf("%d\n", a);
}
#define SIZEOF(arr) (sizeof(arr) / sizeof(*arr))
#define apply(...) \
{ \
int arr[] = {__VA_ARGS__}; \
for(size_t i=0; i<SIZEOF(arr); i++) \
{ \
f(arr[i]); \
} \
}
int main (void)
{
apply(1, 2, 3);
}
Notice that 1) This would be much better off as a variadic function, and 2) it would be even better if you get rid of the variadic nonsense entirely and simply make a function such as
int f (size_t n, int array[n])
In order to make compiler happy I have to count params passed to A(), otherwise gcc raises "warning: ISO C99 requires rest arguments to be used" when pedantic flag is on and only one param is passed
#include <stdio.h>
/* Count params */
#define N_ARGS(...) N_ARGS_IMPL(__VA_ARGS__,n,n,n,n,n,n,n,n,n,1,1)
#define N_ARGS_IMPL(_0,_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N
#define A_fmt_void
#define A_arg_void
/* link */
#define A_fmt_link_1(fmt) " href=\""fmt"\""
#define A_fmt_link_n(fmt, ...) " href=\""fmt"\""
#define A_fmt_link_N(n, ...) A_fmt_link_##n(__VA_ARGS__)
#define A_fmt_link_X(n, ...) A_fmt_link_N(n,__VA_ARGS__)
#define A_fmt_link(...) A_fmt_link_X(N_ARGS(__VA_ARGS__), __VA_ARGS__)
#define A_arg_link_1(fmt)
#define A_arg_link_n(fmt, ...) , __VA_ARGS__
#define A_arg_link_N(n, ...) A_arg_link_##n(__VA_ARGS__)
#define A_arg_link_X(n, ...) A_arg_link_N(n,__VA_ARGS__)
#define A_arg_link(...) A_arg_link_X(N_ARGS(__VA_ARGS__), __VA_ARGS__)
/* text */
#define A_fmt_text_1(fmt) fmt
#define A_fmt_text_n(fmt, ...) fmt
#define A_fmt_text_N(n, ...) A_fmt_text_##n(__VA_ARGS__)
#define A_fmt_text_X(n, ...) A_fmt_text_N(n,__VA_ARGS__)
#define A_fmt_text(...) A_fmt_text_X(N_ARGS(__VA_ARGS__), __VA_ARGS__)
#define A_arg_text_1(fmt)
#define A_arg_text_n(fmt, ...) , __VA_ARGS__
#define A_arg_text_N(n, ...) A_arg_text_##n(__VA_ARGS__)
#define A_arg_text_X(n, ...) A_arg_text_N(n,__VA_ARGS__)
#define A_arg_text(...) A_arg_text_X(N_ARGS(__VA_ARGS__), __VA_ARGS__)
/* macro */
#define A(link, text) \
printf("<a"A_fmt_##link">"A_fmt_##text"</a>\n" A_arg_##link A_arg_##text)
int main(void)
{
A(link(), void);
A(void, text());
A(link("http://www.google.es"), void);
A(link("%s/%s", "http://www.google.es", "home"), text("Visit google"));
A(void, text("%s today", "Visit google"));
A(link("http://%s/%s", "www.google.es", "home"), text("%s today", "Visit google"));
A(void,void);
return 0;
}
With this implementation of N_ARGS I can use only 10 params, is there another way to check if there is more than one param without limit in macro?
I know , ## __VA_ARGS__ gcc extension but I want to avoid warnings
Finally I've fixed using __ extension__
#include <stdio.h>
#define A_fmt_void
#define A_arg_void
#define A_fmt_link(fmt, ...) " href=\""fmt"\""
#define A_arg_link(fmt, ...) , ## __VA_ARGS__
#define A_fmt_text(fmt, ...) fmt
#define A_arg_text(fmt, ...) , ## __VA_ARGS__
#define A(link, text) \
__extension__ printf("<a" A_fmt_##link ">" A_fmt_##text "</a>\n" A_arg_##link A_arg_##text)
int main(void)
{
A(
link("%s", "http://wwww.google.com"),
text("%s", "Visit google")
);
A(
link("http://wwww.google.com"),
void
);
A(
void,
text("Visit google")
);
A(
void,
void
);
return 0;
}
This prevents warnings when pedantic flag is on :)