Related
Ultimately, what I want is this: first, have a list of variable names declared as a C preprocessor macro; say, in test_cpp.c:
#define VARLIST \
var_one, \
var_two, \
var_three, \
var_four
These would eventually be actual variable names in code - but, of course, the preprocessor does not know (or even has a concept of) that at this time.
To make sure the macro has been parsed correctly, I use this command (awk to get rid of the preamble defines in the gcc -E preprocessor output):
$ gcc -E -dD test_cpp.c | awk 'BEGIN{prn=0} /# 1 "test_cpp.c"/ {prn=1} prn==1 {print}'
# 1 "test_cpp.c"
#define VARLIST var_one, var_two, var_three, var_four
So far, so good.
Now: second, I'd like to use this list - that is, I'd like to (pre)process it - and prepend and append characters to each element (token) of the VARLIST, so that I end up with the equivalent of the following macros:
#define VARLIST_QUOTED "var_one", "var_two", "var_three", "var_four"
#define VARLIST_PTR &var_one, &var_two, &var_three, &var_four
... which I could ultimately use in code as, say:
char varnames[][16] = { VARLIST_QUOTED };
( ... which then would end up like this in compiled code, inspected in debugger:
(gdb) p varnames
$1 = {"var_one\000\000\000\000\000\000\000\000",
"var_two\000\000\000\000\000\000\000\000",
"var_three\000\000\000\000\000\000",
"var_four\000\000\000\000\000\000\000"}
)
I'm guessing, at this time the preprocessor wouldn't know & is intended to be an "address-of" operator, although I think it has special handling for double quotes.
In any case, I think that such "lists" in the preprocessor are handled via Variadic Macros (The C Preprocessor), where there is an identifier __VA_ARGS__. Unfortunately, I do not understand this very well: I tried the first thing that came to mind - again, test_cpp.c:
#define VARLIST \
var_one, \
var_two, \
var_three, \
var_four
#define do_prepend(...) &##__VA_ARGS__
#define VARLIST_PTR do_prepend(VARLIST)
void* vars_ptr[] = { VARLIST_PTR };
Then if I run the preprocessor, I get this:
$ gcc -E -dD test_cpp.c | awk 'BEGIN{prn=0} /# 1 "test_cpp.c"/ {prn=1} prn==1 {print}' | sed '/^$/d;G'
test_cpp.c:8:25: error: pasting "&" and "VARLIST" does not give a valid preprocessing token
8 | #define do_prepend(...) &##__VA_ARGS__
| ^
test_cpp.c:9:21: note: in expansion of macro 'do_prepend'
9 | #define VARLIST_PTR do_prepend(VARLIST)
| ^~~~~~~~~~
test_cpp.c:11:22: note: in expansion of macro 'VARLIST_PTR'
11 | void* vars_ptr[] = { VARLIST_PTR };
| ^~~~~~~~~~~
# 1 "test_cpp.c"
#define VARLIST var_one, var_two, var_three, var_four
#define do_prepend(...) & ##__VA_ARGS__
#define VARLIST_PTR do_prepend(VARLIST)
void* vars_ptr[] = { &var_one, var_two, var_three, var_four };
It does show an error - but ultimately, the preprocessor did prepend a single ampersand & to the first variable in the array vars_ptr, as I wanted it to ...
The question is, then: can it prepend an ampersand & to all the entries in the list VARLIST without errors (and likewise, can it both prepend and append a double quote " to all the entries in the list VARLIST without errors) - and if so, how?
Sounds like a job for X macros:
#include <stdio.h>
#define VARS \
X(var_one) \
X(var_two) \
X(var_three) \
X(var_four)
// Define all the variables as ints (just for the example)
#define X(V) int V=0;
VARS
#undef X
// Define the array of variable pointers
#define X(V) &V,
void* vars_ptr[] = { VARS };
#undef X
// Define the array of variable name strings
#define X(V) #V,
const char *var_names[] = { VARS };
#undef X
// Set a few variable values and print out the name/value of all variables
int main()
{
var_one = 9;
var_two = 2;
for(unsigned i = 0; i < sizeof(var_names)/sizeof(var_names[0]); i++)
{
printf("%s=%d\n", var_names[i], *(int *)vars_ptr[i]);
}
return 0;
}
Ok, seems I found an answer, mostly thanks to Is it possible to iterate over arguments in variadic macros? (see also Expand a macro in a macro); this is test_cpp.c:
#define VARLIST \
var_one, \
var_two, \
var_three, \
var_four
// Make a FOREACH macro
#define FE_0(WHAT)
#define FE_1(WHAT, X) WHAT(X)
#define FE_2(WHAT, X, ...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT, X, ...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT, X, ...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT, X, ...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
//... repeat as needed
#define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME
#define FOR_EACH(action,...) \
GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,__VA_ARGS__)
#define XSTR(x) STR(x)
#define STR(x) #x
// original: https://stackoverflow.com/a/11994395
//#define QUALIFIER(X) X::
//#define QUALIFIED(NAME,...) FOR_EACH(QUALIFIER,__VA_ARGS__)NAME
#define POINTERER(X) &X,
#define POINTERIFIED(NAME,...) FOR_EACH(POINTERER,__VA_ARGS__)NAME
// leave first argument (from original QUALIFIED) empty here!
#define vptrs POINTERIFIED(,VARLIST)
void* vars_ptr[] = { vptrs };
//#define DQUOTE " // no need for DQUOTE;
// if we just use the number/hash sign, X gets automatically quoted with double quotes!
// (don't forget the comma at the end!)
#define DQUOTERER(X) #X,
#define DQUOTERIFIED(NAME,...) FOR_EACH(DQUOTERER,__VA_ARGS__)NAME
// leave first argument (from original QUALIFIED) empty here!
#define vnames DQUOTERIFIED(,VARLIST)
char vars_names[][16] = { vnames };
... and this is the output of the preprocessor:
$ gcc -E -dD test_cpp.c | awk 'BEGIN{prn=0} /# 1 "test_cpp.c"/ {prn=1} prn==1 {print}' | sed '/^$/d;G'
# 1 "test_cpp.c"
#define VARLIST var_one, var_two, var_three, var_four
#define FE_0(WHAT)
#define FE_1(WHAT,X) WHAT(X)
#define FE_2(WHAT,X,...) WHAT(X)FE_1(WHAT, __VA_ARGS__)
#define FE_3(WHAT,X,...) WHAT(X)FE_2(WHAT, __VA_ARGS__)
#define FE_4(WHAT,X,...) WHAT(X)FE_3(WHAT, __VA_ARGS__)
#define FE_5(WHAT,X,...) WHAT(X)FE_4(WHAT, __VA_ARGS__)
#define GET_MACRO(_0,_1,_2,_3,_4,_5,NAME,...) NAME
#define FOR_EACH(action,...) GET_MACRO(_0,__VA_ARGS__,FE_5,FE_4,FE_3,FE_2,FE_1,FE_0)(action,__VA_ARGS__)
#define XSTR(x) STR(x)
#define STR(x) #x
#define POINTERER(X) &X,
#define POINTERIFIED(NAME,...) FOR_EACH(POINTERER,__VA_ARGS__)NAME
#define vptrs POINTERIFIED(,VARLIST)
void* vars_ptr[] = { &var_one,&var_two,&var_three,&var_four, };
#define DQUOTERER(X) #X,
#define DQUOTERIFIED(NAME,...) FOR_EACH(DQUOTERER,__VA_ARGS__)NAME
#define vnames DQUOTERIFIED(,VARLIST)
char vars_names[][16] = { "var_one","var_two","var_three","var_four", };
So, ultimately, I got my output as desired - and no preprocessor errors/warnings, as far as I can tell:
void* vars_ptr[] = { &var_one,&var_two,&var_three,&var_four, };
char vars_names[][16] = { "var_one","var_two","var_three","var_four", };
As already mentioned, you are more or less literally describing the purpose of "X macros".
An alternative, arguably somewhat more readable way of writing them is to first declare a macro list, then pass a macro to that list. As in
"here is a function-like macro, run it with all the arguments listed", rather than
"here is the function-like macro X, run macro X with all the arguments listed".
This allows you to give macros meaningful names, optionally group all macros belonging to the list somewhere, and it eliminates the need to #undef.
#include <stdio.h>
// note the absence of commas
#define VARLIST(X) \
X(var_one) \
X(var_two) \
X(var_three) \
X(var_four) \
int main (void)
{
char varnames[][16] =
{
#define VARLIST_QUOTED(name) #name, /* "stringification operator" */
VARLIST(VARLIST_QUOTED) /* no semicolon or comma here */
};
#define VARLIST_DECL_VARS(name) int name; /* declare a bunch of int */
VARLIST(VARLIST_DECL_VARS)
int* const pointers[] =
{
#define VARLIST_PTR(name) &name, /* declare an array of pointers to previous ints */
VARLIST(VARLIST_PTR)
};
var_two = 123;
printf("%s has value %d and address %p\n",
varnames[1],
var_two,
pointers[1]);
}
I have a big code base that looks like this:
#define LIB_TUP_0_(A, B, C) A
#define LIB_TUP_0(TUP) LIB_TUP_0_ TUP
#define LIB_TUP_1_(A, B, C) B
#define LIB_TUP_1(TUP) LIB_TUP_1_ TUP
#define LIB_TUP_2_(A, B, C) C
#define LIB_TUP_2(TUP) LIB_TUP_2_ TUP
#define LIB_PARAM_PFX LIB_TUP_0
#define LIB_PARAM_T LIB_TUP_1
#define LIB_PARAM_NAME LIB_TUP_2
#define F(PARAM) \
F_(LIB_PARAM_PFX(PARAM), LIB_PARAM_T(PARAM))
#define FS(PARAM) \
FS_(LIB_PARAM_T(PARAM), LIB_PARAM_PFX(PARAM), LIB_PARAM_NAME(PARAM))
#define F_(PFX, T) \
T PFX##_hello(T a);
#define FS_(T, PFX, NAME) \
T PFX##_hello(T NAME) { return NAME; }
with a header definition F and a source definition FS for a lot of things.
The problem is that PARAM is a (new) standard way to provide parameters to the entire library and it needs to be a tuple of the form (PFX, T, NAME). Some macros though only require certain parameters from this tuple or need to be passed in a different order.
The problem is that a lot of code doesn't use the 'glue' macro and I thought if there is a way to not have to use it...
This is an undesired, but working example:
#define LIB_GLUE(a, b) a##b
#define LIB_TUP_0_(A, B, C) A
#define LIB_TUP_0(TUP) LIB_TUP_0_ TUP
#define LIB_TUP_1_(A, B, C) B
#define LIB_TUP_1(TUP) LIB_TUP_1_ TUP
#define LIB_TUP_2_(A, B, C) C
#define LIB_TUP_2(TUP) LIB_TUP_2_ TUP
#define LIB_PARAM_PFX LIB_TUP_0
#define LIB_PARAM_T LIB_TUP_1
#define LIB_PARAM_NAME LIB_TUP_2
#define F(PARAM) \
F_(LIB_PARAM_PFX(PARAM), LIB_PARAM_T(PARAM))
#define FS(PARAM) \
FS_(LIB_PARAM_T(PARAM), LIB_PARAM_PFX(PARAM), LIB_PARAM_NAME(PARAM))
#define F_(PFX, T) \
T LIB_GLUE(PFX, _hello)(T a);
#define FS_(T, PFX, NAME) \
T LIB_GLUE(PFX, _hello)(T NAME) { return NAME; }
#define M (l, int, b)
F((l, int, ))
FS(M)
Undesired because I can't (maybe) afford to change every PFX##_hello to LIB_GLUE(PFX, _hello) in the entire code base. So I'm here asking if there is any way out of this without having massive refactoring issues.
background
I'm trying to make automatic generator of Lua-C interface using C macros. The biggest problem was to make it general for varying number of arguments, which I resolved by using __VA_ARGS__ with help of this answer: Is it possible to iterate over arguments in variadic macros?
Simpler almost working solution
this solution almost works, but it produce some redudant commas (nottice ,,,, in output)
// helper macros for iteration over __VA_ARGS__
#define ARG1(WHAT,X,...) WHAT(X)ARG2(WHAT,__VA_ARGS__)
#define ARG2(WHAT,X,...) WHAT(X)ARG3(WHAT,__VA_ARGS__)
#define ARG3(WHAT,X,...) WHAT(X)ARG4(WHAT,__VA_ARGS__)
#define ARG4(WHAT,X,...) WHAT(X)ARG5(WHAT,__VA_ARGS__)
#define ARG5(WHAT,X,...) WHAT(X)ARG6(WHAT,__VA_ARGS__)
#define ARG6(WHAT,X,...) WHAT(X)//ARG2(__VA_ARGS__)
// macros dispatch propper type of Lua::get
#define LUA_GET_int(i) Lua::getInt(L,i)
#define LUA_GET_long(i) Lua::getInt(L,i)
#define LUA_GET_float(i) (float)Lua::getDouble(L,i)
#define LUA_GET_double(i) Lua::getDouble(L,i)
#define LUA_GET_string(i) Lua::getString(L,i)
#define LUA_PUSH_int(a) lua_pushnumber(L,a)
#define LUA_PUSH_float(a) lua_pushnumber(L,a)
#define LUA_PUSH_double(a) lua_pushnumber(L,a)
#define LUA_PUSH_float(a) lua_pushstring(L,a)
#define LUA_GET_(T)
#define LUA_GET(T) ,LUA_GET_##T(i++) // commas come from here
#define MAKE_LUA_FUNC(TR,fname,T1,...) int l_##fname(lua_State * L){ int i=0; LUA_PUSH_##TR( fname( LUA_GET_##T1(i++) ARG1(LUA_GET,__VA_ARGS__) ) ); return 1; }
// interface for function:
// double add3(float, int, double );
MAKE_LUA_FUNC( double, add3, float, int, double )
// output:
// 'int l_add3(lua_State * L){ int i=0; lua_pushnumber(L,add3((float)Lua::getDouble(L,i++) ,Lua::getInt(L,i++),Lua::getDouble(L,i++),,,, )); return 1; }'
Working but less-nice solution
I had to duplicate LUA_GET_ macros for case when it is first in argument list (without comma) and otherwise (with comma in front)
// begin of argument list => no commas
#define LUA_GET_int(i) Lua::getInt(L,i)
#define LUA_GET_long(i) Lua::getInt(L,i)
#define LUA_GET_float(i) (float)Lua::getDouble(L,i)
#define LUA_GET_double(i) Lua::getDouble(L,i)
#define LUA_GET_string(i) Lua::getString(L,i)
// rest of argument list => with commas
#define LUA_GET__int(i) ,Lua::getInt(L,i)
#define LUA_GET__long(i) ,Lua::getInt(L,i)
#define LUA_GET__float(i) ,(float)Lua::getDouble(L,i)
#define LUA_GET__double(i) ,Lua::getDouble(L,i)
#define LUA_GET__string(i) ,Lua::getString(L,i)
#define LUA_PUSH_int(a) lua_pushnumber(L,a)
#define LUA_PUSH_float(a) lua_pushnumber(L,a)
#define LUA_PUSH_double(a) lua_pushnumber(L,a)
#define LUA_PUSH_float(a) lua_pushstring(L,a)
#define LUA_GET_(T)
#define LUA_GET__(T)
#define LUA_GET(T) LUA_GET__##T(i++)
#define MAKE_LUA_FUNC(TR,fname,T1,...) int l_##fname(lua_State * L){ int i=0; LUA_PUSH_##TR( fname( LUA_GET_##T1(i++) ARG1(LUA_GET,__VA_ARGS__) ) ); return 1; }
// MAKE_LUA_FUNC( double, add3, float, int, double )
// output:
// int l_add3(lua_State * L){ int i=0; lua_pushnumber(L,add3( (float)Lua::getDouble(L,i++) ,Lua::getInt(L,i++),Lua::getDouble(L,i++) )); return 1; }
Is it possible to make it simpler / nicer ?
NOTE - for debugging I found very useful this Seeing expanded C macros in particular https://stackoverflow.com/a/31460434/1291544
You need to count the number of arguments you have, and then call the corresponding ARG# macro.
#define ARGS_N(M,...) \
ARGS_N__(__VA_ARGS__, 6, 5, 4, 3, 2, 1)(M, __VA_ARGS__)
#define ARGS_N__(_1, _2, _3, _4, _5, _6, X, ...) ARGS_##X
#define ARGS_1(M, X) M(X)
#define ARGS_2(M, X, ...) M(X)ARGS_1(M, __VA_ARGS__)
#define ARGS_3(M, X, ...) M(X)ARGS_2(M, __VA_ARGS__)
#define ARGS_4(M, X, ...) M(X)ARGS_3(M, __VA_ARGS__)
#define ARGS_5(M, X, ...) M(X)ARGS_4(M, __VA_ARGS__)
#define ARGS_6(M, X, ...) M(X)ARGS_5(M, __VA_ARGS__)
Now, change MAKE_LUA_FUNC to call ARGS_N instead of your ARG1.
The way the counting technique works is that ARGS_N invokes the helper ARGS_N__ with the variable arguments, and then pads out the invocation with additional arguments. ARGS_N__ does the counting by always utilizing the 7th argument. So, if ARGS_N is provided 4 variable arguments after the first one, ARGS_N__ will produce ARGS_4, because in that case, in the padding provided by ARGS_N, 4 would be the 7th argument.
ARGS_N__(__VA_ARGS__, 6, 5, 4, 3, 2, 1)(M, __VA_ARGS__)
. .
/|\ /|\
| |
If this has 4 arguments
|
This would be the 7th argument
This is the same technique that was shown in the answer you pointed to. However, that version was a bit more complicated than the version I am illustrating for you, so hopefully you will find this explanation helpful.
Is there some way of getting optional parameters with C++ Macros? Some sort of overloading would be nice too.
Here's one way to do it. It uses the list of arguments twice, first to form the name of the helper macro, and then to pass the arguments to that helper macro. It uses a standard trick to count the number of arguments to a macro.
enum
{
plain = 0,
bold = 1,
italic = 2
};
void PrintString(const char* message, int size, int style)
{
}
#define PRINT_STRING_1_ARGS(message) PrintString(message, 0, 0)
#define PRINT_STRING_2_ARGS(message, size) PrintString(message, size, 0)
#define PRINT_STRING_3_ARGS(message, size, style) PrintString(message, size, style)
#define GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
#define PRINT_STRING_MACRO_CHOOSER(...) \
GET_4TH_ARG(__VA_ARGS__, PRINT_STRING_3_ARGS, \
PRINT_STRING_2_ARGS, PRINT_STRING_1_ARGS, )
#define PRINT_STRING(...) PRINT_STRING_MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
int main(int argc, char * const argv[])
{
PRINT_STRING("Hello, World!");
PRINT_STRING("Hello, World!", 18);
PRINT_STRING("Hello, World!", 18, bold);
return 0;
}
This makes it easier for the caller of the macro, but not the writer.
With great respect to Derek Ledbetter for his answer — and with apologies for reviving an old question.
Getting an understanding of what it was doing and picking up elsewhere on the ability to preceed the __VA_ARGS__ with ## allowed me to come up with a variation...
// The multiple macros that you would need anyway [as per: Crazy Eddie]
#define XXX_0() <code for no arguments>
#define XXX_1(A) <code for one argument>
#define XXX_2(A,B) <code for two arguments>
#define XXX_3(A,B,C) <code for three arguments>
#define XXX_4(A,B,C,D) <code for four arguments>
// The interim macro that simply strips the excess and ends up with the required macro
#define XXX_X(x,A,B,C,D,FUNC, ...) FUNC
// The macro that the programmer uses
#define XXX(...) XXX_X(,##__VA_ARGS__,\
XXX_4(__VA_ARGS__),\
XXX_3(__VA_ARGS__),\
XXX_2(__VA_ARGS__),\
XXX_1(__VA_ARGS__),\
XXX_0(__VA_ARGS__)\
)
For non-experts like me who stumble upon the answer, but can't quite see how it works, I'll step through the actual processing, starting with the following code...
XXX();
XXX(1);
XXX(1,2);
XXX(1,2,3);
XXX(1,2,3,4);
XXX(1,2,3,4,5); // Not actually valid, but included to show the process
Becomes...
XXX_X(, XXX_4(), XXX_3(), XXX_2(), XXX_1(), XXX_0() );
XXX_X(, 1, XXX_4(1), XXX_3(1), XXX_2(1), XXX_1(1), XXX_0(1) );
XXX_X(, 1, 2, XXX_4(1,2), XXX_3(1,2), XXX_2(1,2), XXX_1(1,2), XXX_0(1,2) );
XXX_X(, 1, 2, 3, XXX_4(1,2,3), XXX_3(1,2,3), XXX_2(1,2,3), XXX_1(1,2,3), XXX_0(1,2,3) );
XXX_X(, 1, 2, 3, 4, XXX_4(1,2,3,4), XXX_3(1,2,3,4), XXX_2(1,2,3,4), XXX_1(1,2,3,4), XXX_0(1,2,3,4) );
XXX_X(, 1, 2, 3, 4, 5, XXX_4(1,2,3,4,5), XXX_3(1,2,3,4,5), XXX_2(1,2,3,4,5), XXX_1(1,2,3,4,5), XXX_0(1,2,3,4,5) );
Which becomes just the sixth argument...
XXX_0();
XXX_1(1);
XXX_2(1,2);
XXX_3(1,2,3);
XXX_4(1,2,3,4);
5;
PS: Remove the #define for XXX_0 to get a compile error [ie: if a no-argument option is not allowed].
PPS: Would be nice to have the invalid situations (eg: 5) be something that gives a clearer compilation error to the programmer!
PPPS: I'm not an expert, so I'm very happy to hear comments (good, bad or other)!
With greatest respect to Derek Ledbetter, David Sorkovsky, Syphorlate for their answers, together with the ingenious method to detect empty macro arguments by Jens Gustedt at
https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
finally I come out with something that incorporates all the tricks, so that the solution
Uses only standard C99 macros to achieve function overloading, no GCC/CLANG/MSVC extension involved (i.e., comma swallowing by the specific expression , ##__VA_ARGS__ for GCC/CLANG, and implicit swallowing by ##__VA_ARGS__ for MSVC). So feel free to pass the missing --std=c99 to your compiler if you wish =)
Works for zero argument, as well as unlimited number of arguments, if you expand it further to suit your needs
Works reasonably cross-platform, at least tested for
GNU/Linux + GCC (GCC 4.9.2 on CentOS 7.0 x86_64)
GNU/Linux + CLANG/LLVM, (CLANG/LLVM 3.5.0 on CentOS 7.0 x86_64)
OS X + Xcode, (XCode 6.1.1 on OS X Yosemite 10.10.1)
Windows + Visual Studio, (Visual Studio 2013 Update 4 on Windows 7 SP1 64 bits)
For the lazies, just skip to the very last of this post to copy the source. Below is the detailed explanation, which hopefully helps and inspires all people looking for the general __VA_ARGS__ solutions like me. =)
Here's how it goes. First define the user-visible overloaded "function", I named it create, and the related actual function definition realCreate, and the macro definitions with different number of arguments CREATE_2, CREATE_1, CREATE_0, as shown below:
#define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
#define CREATE_2(x, y) realCreate(x, y)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_0() CREATE_1(0)
The MACRO_CHOOSER(__VA_ARGS__) part ultimately resolves to the macro definition names, and the second (__VA_ARGS__) part comprises their parameter lists. So a user's call to create(10) resolves to CREATE_1(10), the CREATE_1 part comes from MACRO_CHOOSER(__VA_ARGS__), and the (10) part comes from the second (__VA_ARGS__).
The MACRO_CHOOSER uses the trick that, if __VA_ARGS__ is empty, the following expression is concatenated into a valid macro call by the preprocessor:
NO_ARG_EXPANDER __VA_ARGS__ () // simply shrinks to NO_ARG_EXPANDER()
Ingeniusly, we can define this resulting macro call as
#define NO_ARG_EXPANDER() ,,CREATE_0
Note the two commas, they are explained soon. The next useful macro is
#define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
so the calls of
create();
create(10);
create(20, 20);
are actually expanded to
CHOOSE_FROM_ARG_COUNT(,,CREATE_0)();
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 10 ())(10);
CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER 20, 20 ())(20, 20);
As the macro name suggests, we are to count number of arguments later. Here comes another trick: the preprocessor only does simple text replacement. It infers the number of arguments of a macro call merely from the number of commas it sees inside the parentheses. The actual "arguments" separated by commas need not to be of valid syntax. They can be any text. That's to say, in the above example, NO_ARG_EXPANDER 10 () is counted as 1 argument for the middle call. NO_ARG_EXPANDER 20 and 20 () are counted as 2 arguments for the bottom call respectively.
If we use the following helper macros to further expand them
##define CHOOSE_FROM_ARG_COUNT(...) \
FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
#define FUNC_RECOMPOSER(argsWithParentheses) \
FUNC_CHOOSER argsWithParentheses
The trailing , after CREATE_1 is a work-around for GCC/CLANG, suppressing a (false positive) error saying that ISO C99 requires rest arguments to be used when passing -pedantic to your compiler. The FUNC_RECOMPOSER is a work-around for MSVC, or it can not count number of arguments (i.e., commas) inside the parentheses of macro calls correctly. The results are further resolved to
FUNC_CHOOSER (,,CREATE_0, CREATE_2, CREATE_1, )();
FUNC_CHOOSER (NO_ARG_EXPANDER 10 (), CREATE_2, CREATE_1, )(10);
FUNC_CHOOSER (NO_ARG_EXPANDER 20, 20 (), CREATE_2, CREATE_1, )(20, 20);
As the eagle-eyed you may have seen, the last only step we need is to employ a standard argument counting trick to finally pick the wanted macro version names:
#define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
which resolves the results to
CREATE_0();
CREATE_1(10);
CREATE_2(20, 20);
and certainly gives us the desired, actual function calls:
realCreate(0, 0);
realCreate(10, 10);
realCreate(20, 20);
Putting all together, with some rearrangement of statements for better readability, the whole source of the 2-argument example is here:
#include <stdio.h>
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
#define CREATE_2(x, y) realCreate(x, y)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_0() CREATE_1(0)
#define FUNC_CHOOSER(_f1, _f2, _f3, ...) _f3
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(...) FUNC_RECOMPOSER((__VA_ARGS__, CREATE_2, CREATE_1, ))
#define NO_ARG_EXPANDER() ,,CREATE_0
#define MACRO_CHOOSER(...) CHOOSE_FROM_ARG_COUNT(NO_ARG_EXPANDER __VA_ARGS__ ())
#define create(...) MACRO_CHOOSER(__VA_ARGS__)(__VA_ARGS__)
int main()
{
create();
create(10);
create(20, 20);
//create(30, 30, 30); // Compilation error
return 0;
}
Although complicated, ugly, burdening the API developer, there comes a solution for overloading and setting optional parameters of C/C++ functions to us crazy people. The usage of the out-coming overloaded APIs become very enjoyable and pleasant. =)
If there is any further possible simplification of this approach, please do let me know at
https://github.com/jason-deng/C99FunctionOverload
Again special thanks to all of the brilliant people that inspired and led me to achieve this piece of work! =)
C++ macros haven't changed from C. Since C didn't have overloading and default arguments for functions, it certainly didn't have them for macros. So to answer your question: no, those features don't exist for macros. Your only option is to define multiple macros with different names (or not use macros at all).
As a sidenote: In C++ it's generally considered good practice to move away from macros as much as possible. If you need features like this, there's a good chance you're overusing macros.
For anyone painfully searching some VA_NARGS solution that works with Visual C++. Following macro worked for me flawlessly(also with zero parameters!) in visual c++ express 2010:
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,N,...) N
#define VA_NUM_ARGS_IMPL_(tuple) VA_NUM_ARGS_IMPL tuple
#define VA_NARGS(...) bool(#__VA_ARGS__) ? (VA_NUM_ARGS_IMPL_((__VA_ARGS__, 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
If you want a macro with optional parameters you can do:
//macro selection(vc++)
#define SELMACRO_IMPL(_1,_2,_3, N,...) N
#define SELMACRO_IMPL_(tuple) SELMACRO_IMPL tuple
#define mymacro1(var1) var1
#define mymacro2(var1,var2) var2*var1
#define mymacro3(var1,var2,var3) var1*var2*var3
#define mymacro(...) SELMACRO_IMPL_((__VA_ARGS__, mymacro3(__VA_ARGS__), mymacro2(__VA_ARGS__), mymacro1(__VA_ARGS__)))
That worked for me aswell in vc. But it doesn't work for zero parameters.
int x=99;
x=mymacro(2);//2
x=mymacro(2,2);//4
x=mymacro(2,2,2);//8
gcc/g++ supports varargs macros but I don't think this is standard, so use it at your own risk.
More concise version of Derek Ledbetter's code:
enum
{
plain = 0,
bold = 1,
italic = 2
};
void PrintString(const char* message = NULL, int size = 0, int style = 0)
{
}
#define PRINT_STRING(...) PrintString(__VA_ARGS__)
int main(int argc, char * const argv[])
{
PRINT_STRING("Hello, World!");
PRINT_STRING("Hello, World!", 18);
PRINT_STRING("Hello, World!", 18, bold);
return 0;
}
#include <stdio.h>
#define PP_NARG(...) \
PP_NARG_(__VA_ARGS__,PP_RSEQ_N())
#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 PP_CONCAT(a,b) PP_CONCAT_(a,b)
#define PP_CONCAT_(a,b) a ## b
#define THINK(...) PP_CONCAT(THINK_, PP_NARG(__VA_ARGS__))(__VA_ARGS__)
#define THINK_0() THINK_1("sector zz9 plural z alpha")
#define THINK_1(location) THINK_2(location, 42)
#define THINK_2(location,answer) THINK_3(location, answer, "deep thought")
#define THINK_3(location,answer,computer) \
printf ("The answer is %d. This was calculated by %s, and a computer to figure out what this"
" actually means will be build in %s\n", (answer), (computer), (location))
int
main (int argc, char *argv[])
{
THINK (); /* On compilers other than GCC you have to call with least one non-default argument */
}
DISCLAIMER: Mostly harmless.
As a big fan of horrible macro monsters, I wanted to expand on Jason Deng's answer and make it actually usable. (For better or worse.) The original is not very nice to use because you need to modify the big alphabet soup every time you want to make a new macro and it's even worse if you need different amount of arguments.
So I made a version with these features:
0 argument case works
1 to 16 arguments without any modifications to the messy part
Easy to write more macro functions
Tested in gcc 10, clang 9, Visual Studio 2017
Currently I just made 16 argument maximum, but if you need more (really now? you're just getting silly...) you can edit FUNC_CHOOSER and CHOOSE_FROM_ARG_COUNT, then add some commas to NO_ARG_EXPANDER.
Please see Jason Deng's excellent answer for more details on the implementation, but I'll just put the code here:
#include <stdio.h>
void realCreate(int x, int y)
{
printf("(%d, %d)\n", x, y);
}
// This part you put in some library header:
#define FUNC_CHOOSER(_f0, _f1, _f2, _f3, _f4, _f5, _f6, _f7, _f8, _f9, _f10, _f11, _f12, _f13, _f14, _f15, _f16, ...) _f16
#define FUNC_RECOMPOSER(argsWithParentheses) FUNC_CHOOSER argsWithParentheses
#define CHOOSE_FROM_ARG_COUNT(F, ...) FUNC_RECOMPOSER((__VA_ARGS__, \
F##_16, F##_15, F##_14, F##_13, F##_12, F##_11, F##_10, F##_9, F##_8,\
F##_7, F##_6, F##_5, F##_4, F##_3, F##_2, F##_1, ))
#define NO_ARG_EXPANDER(FUNC) ,,,,,,,,,,,,,,,,FUNC ## _0
#define MACRO_CHOOSER(FUNC, ...) CHOOSE_FROM_ARG_COUNT(FUNC, NO_ARG_EXPANDER __VA_ARGS__ (FUNC))
#define MULTI_MACRO(FUNC, ...) MACRO_CHOOSER(FUNC, __VA_ARGS__)(__VA_ARGS__)
// When you need to make a macro with default arguments, use this:
#define create(...) MULTI_MACRO(CREATE, __VA_ARGS__)
#define CREATE_0() CREATE_1(0)
#define CREATE_1(x) CREATE_2(x, 0)
#define CREATE_2(x, y) \
do { \
/* put whatever code you want in the last macro */ \
realCreate(x, y); \
} while(0)
int main()
{
create();
create(10);
create(20, 20);
//create(30, 30, 30); // Compilation error
return 0;
}
That's not really what the preprocessor is designed for.
That said, if you want to enter into the area of seriously challenging macro programming with a modicum of readability, you should take a look at the Boost preprocessor library. After all, it wouldn't be C++ if there weren't three completely Turing compatible levels of programming (preprocessor, template metaprogramming, and base level C++)!
#define MY_MACRO_3(X,Y,Z) ...
#define MY_MACRO_2(X,Y) MY_MACRO(X,Y,5)
#define MY_MACRO_1(X) MY_MACRO(X,42,5)
You know at the point of call how many args you're going to pass in so there's really no need for overloading.
You can use BOOST_PP_OVERLOAD from a boost library.
Example from official boost doc:
#include <boost/preprocessor/facilities/overload.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/arithmetic/add.hpp>
#define MACRO_1(number) MACRO_2(number,10)
#define MACRO_2(number1,number2) BOOST_PP_ADD(number1,number2)
#if !BOOST_PP_VARIADICS_MSVC
#define MACRO_ADD_NUMBERS(...) BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__)
#else
// or for Visual C++
#define MACRO_ADD_NUMBERS(...) \
BOOST_PP_CAT(BOOST_PP_OVERLOAD(MACRO_,__VA_ARGS__)(__VA_ARGS__),BOOST_PP_EMPTY())
#endif
MACRO_ADD_NUMBERS(5) // output is 15
MACRO_ADD_NUMBERS(3,6) // output is 9
Depending on what you need, you could do it with var args with macros. Now, optional parameters or macro overloading, there is no such thing.
Not directly answering the question, but using the same trick as David Sorkovsky answer and giving a clear example of how to build complex macros.
Just compile this with g++ -E test.cpp -o test && cat test:
// #define GET_FIRST_ARG_0_ARGS(default) (default)
// #define GET_FIRST_ARG_1_ARGS(default, a) (a)
// #define GET_FIRST_ARG_2_ARGS(default, a, b) (a)
// #define GET_FIRST_ARG_3_ARGS(default, a, b, c) (a)
// #define GET_FIRST_ARG_4_ARGS(default, a, b, c, d) (a)
#define GET_FIRST_ARG_MACROS(default, a, b, c, d, macro, ...) macro
#define GET_FIRST_ARG(default, ...) GET_FIRST_ARG_MACROS( \
,##__VA_ARGS__, \
GET_FIRST_ARG_4_ARGS(default, __VA_ARGS__), \
GET_FIRST_ARG_3_ARGS(default, __VA_ARGS__), \
GET_FIRST_ARG_2_ARGS(default, __VA_ARGS__), \
GET_FIRST_ARG_1_ARGS(default, __VA_ARGS__), \
GET_FIRST_ARG_0_ARGS(default, ##__VA_ARGS__), \
)
"0,"; GET_FIRST_ARG(0);
"0,1"; GET_FIRST_ARG(0,1);
"0,1,2"; GET_FIRST_ARG(0,1,2);
"0,1,2,3"; GET_FIRST_ARG(0,1,2,3);
"0,1,2,3,4"; GET_FIRST_ARG(0,1,2,3,4);
To see the output:
# 1 "test.cpp"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "/usr/x86_64-linux-gnu/include/stdc-predef.h" 1 3
# 1 "<command-line>" 2
# 1 "test.cpp"
# 16 "test.cpp"
"0,"; GET_FIRST_ARG_0_ARGS(0);
"0,1"; GET_FIRST_ARG_1_ARGS(0, 1);
"0,1,2"; GET_FIRST_ARG_2_ARGS(0, 1,2);
"0,1,2,3"; GET_FIRST_ARG_3_ARGS(0, 1,2,3);
"0,1,2,3,4"; GET_FIRST_ARG_4_ARGS(0, 1,2,3,4);
Now, a full working program would be:
#include <iostream>
#define GET_FIRST_ARG_0_ARGS(default) (default)
#define GET_FIRST_ARG_1_ARGS(default, a) (a)
#define GET_FIRST_ARG_2_ARGS(default, a, b) (a)
#define GET_FIRST_ARG_3_ARGS(default, a, b, c) (a)
#define GET_FIRST_ARG_4_ARGS(default, a, b, c, d) (a)
#define GET_FIRST_ARG_MACROS(default, a, b, c, d, macro, ...) macro
#define GET_FIRST_ARG(default, ...) GET_FIRST_ARG_MACROS( \
,##__VA_ARGS__, \
GET_FIRST_ARG_4_ARGS(default, __VA_ARGS__), \
GET_FIRST_ARG_3_ARGS(default, __VA_ARGS__), \
GET_FIRST_ARG_2_ARGS(default, __VA_ARGS__), \
GET_FIRST_ARG_1_ARGS(default, __VA_ARGS__), \
GET_FIRST_ARG_0_ARGS(default, ##__VA_ARGS__), \
)
int main(int argc, char const *argv[]) {
"0,"; GET_FIRST_ARG(0);
"0,1"; GET_FIRST_ARG(0,1);
"0,1,2"; GET_FIRST_ARG(0,1,2);
"0,1,2,3"; GET_FIRST_ARG(0,1,2,3);
"0,1,2,3,4"; GET_FIRST_ARG(0,1,2,3,4);
std::cerr << "0, == " << GET_FIRST_ARG(0) << std::endl;
std::cerr << "0,1 == " << GET_FIRST_ARG(0,1) << std::endl;
std::cerr << "0,1,2 == " << GET_FIRST_ARG(0,1,2) << std::endl;
std::cerr << "0,1,2,3 == " << GET_FIRST_ARG(0,1,2,3) << std::endl;
std::cerr << "0,1,2,3,4 == " << GET_FIRST_ARG(0,1,2,3,4) << std::endl;
return 0;
}
Which would output the following by being compiled with g++ test.cpp -o test && ./test:
0, == 0
0,1 == 1
0,1,2 == 1
0,1,2,3 == 1
0,1,2,3,4 == 1
Note: It is important to use () around the macro contents as #define GET_FIRST_ARG_1_ARGS(default, a) (a) to not break in ambiguous expressions when a is just not a integer.
Extra macro for second argument:
#define GET_SECOND_ARG_0_ARGS(default) (default)
#define GET_SECOND_ARG_1_ARGS(default, a) (default)
#define GET_SECOND_ARG_2_ARGS(default, a, b) (b)
#define GET_SECOND_ARG_3_ARGS(default, a, b, c) (b)
#define GET_SECOND_ARG_4_ARGS(default, a, b, c, d) (b)
#define GET_SECOND_ARG_MACROS(default, a, b, c, d, macro, ...) macro
#define GET_SECOND_ARG(default, ...) GET_SECOND_ARG_MACROS( \
,##__VA_ARGS__, \
GET_SECOND_ARG_4_ARGS(default, __VA_ARGS__), \
GET_SECOND_ARG_3_ARGS(default, __VA_ARGS__), \
GET_SECOND_ARG_2_ARGS(default, __VA_ARGS__), \
GET_SECOND_ARG_1_ARGS(default, __VA_ARGS__), \
GET_SECOND_ARG_0_ARGS(default, ##__VA_ARGS__), \
)
None of the above examples (from Derek Ledbetter, David Sorkovsky, and Joe D) to count arguments with macros worked for me using Microsoft VCC 10. The __VA_ARGS__ argument is always considered as a single argument (token-izing it with ## or not), so the argument shifting in which those examples rely doesn't work.
So, short answer, as stated by many others above: no, you can't overload macros or use optional arguments on them.
I am asking this question from an educational/hacking point of view, (I wouldn't really want to code like this).
Is it possible to implement a while loop only using C preprocessor directives. I understand that macros cannot be expanded recursively, so how would this be accomplished?
If you want to implement a while loop, you will need to use recursion in the preprocessor. The easiest way to do recursion is to use a deferred expression. A deferred expression is an expression that requires more scans to fully expand:
#define EMPTY()
#define DEFER(id) id EMPTY()
#define OBSTRUCT(id) id DEFER(EMPTY)()
#define EXPAND(...) __VA_ARGS__
#define A() 123
A() // Expands to 123
DEFER(A)() // Expands to A () because it requires one more scan to fully expand
EXPAND(DEFER(A)()) // Expands to 123, because the EXPAND macro forces another scan
Why is this important? Well when a macro is scanned and expanding, it creates a disabling context. This disabling context will cause a token, that refers to the currently expanding macro, to be painted blue. Thus, once its painted blue, the macro will no longer expand. This is why macros don't expand recursively. However, a disabling context only exists during one scan, so by deferring an expansion we can prevent our macros from becoming painted blue. We will just need to apply more scans to the expression. We can do that using this EVAL macro:
#define EVAL(...) EVAL1(EVAL1(EVAL1(__VA_ARGS__)))
#define EVAL1(...) EVAL2(EVAL2(EVAL2(__VA_ARGS__)))
#define EVAL2(...) EVAL3(EVAL3(EVAL3(__VA_ARGS__)))
#define EVAL3(...) EVAL4(EVAL4(EVAL4(__VA_ARGS__)))
#define EVAL4(...) EVAL5(EVAL5(EVAL5(__VA_ARGS__)))
#define EVAL5(...) __VA_ARGS__
Next, we define some operators for doing some logic(such as if, etc):
#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__
#define CHECK_N(x, n, ...) n
#define CHECK(...) CHECK_N(__VA_ARGS__, 0,)
#define NOT(x) CHECK(PRIMITIVE_CAT(NOT_, x))
#define NOT_0 ~, 1,
#define COMPL(b) PRIMITIVE_CAT(COMPL_, b)
#define COMPL_0 1
#define COMPL_1 0
#define BOOL(x) COMPL(NOT(x))
#define IIF(c) PRIMITIVE_CAT(IIF_, c)
#define IIF_0(t, ...) __VA_ARGS__
#define IIF_1(t, ...) t
#define IF(c) IIF(BOOL(c))
Now with all these macros we can write a recursive WHILE macro. We use a WHILE_INDIRECT macro to refer back to itself recursively. This prevents the macro from being painted blue, since it will expand on a different scan(and using a different disabling context). The WHILE macro takes a predicate macro, an operator macro, and a state(which is the variadic arguments). It keeps applying this operator macro to the state until the predicate macro returns false(which is 0).
#define WHILE(pred, op, ...) \
IF(pred(__VA_ARGS__)) \
( \
OBSTRUCT(WHILE_INDIRECT) () \
( \
pred, op, op(__VA_ARGS__) \
), \
__VA_ARGS__ \
)
#define WHILE_INDIRECT() WHILE
For demonstration purposes, we are just going to create a predicate that checks when number of arguments are 1:
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define IS_1(x) CHECK(PRIMITIVE_CAT(IS_1_, x))
#define IS_1_1 ~, 1,
#define PRED(x, ...) COMPL(IS_1(NARGS(__VA_ARGS__)))
Next we create an operator, which we will just concat two tokens. We also create a final operator(called M) that will process the final output:
#define OP(x, y, ...) CAT(x, y), __VA_ARGS__
#define M(...) CAT(__VA_ARGS__)
Then using the WHILE macro:
M(EVAL(WHILE(PRED, OP, x, y, z))) //Expands to xyz
Of course, any kind of predicate or operator can be passed to it.
Take a look at the Boost preprocessor library, which allows you to write loops in the preprocessor, and much more.
You use recursive include files. Unfortunately, you can't iterate the loop more than the maximum depth that the preprocessor allows.
It turns out that C++ templates are Turing Complete and can be used in similar ways. Check out Generative Programming
I use meta-template programming for this purpose, its fun once you get a hang of it. And very useful at times when used with discretion. Because as mentioned its turing complete, to the point where you can even cause the compiler to get into an infinite loop, or stack-overflow! There is nothing like going to get some coffee just to find your compilation is using up 30+ gigabytes of memory and all the CPU to compile your infinite loop code!
well, not that it's a while loop, but a counter loop, nonetheless the loop is possible in clean CPP (no templates and no C++)
#ifdef pad_always
#define pad(p,f) p##0
#else
#define pad0(p,not_used) p
#define pad1(p,not_used) p##0
#define pad(p,f) pad##f(p,)
#endif
// f - padding flag
// p - prefix so far
// a,b,c - digits
// x - action to invoke
#define n0(p,x)
#define n1(p,x) x(p##1)
#define n2(p,x) n1(p,x) x(p##2)
#define n3(p,x) n2(p,x) x(p##3)
#define n4(p,x) n3(p,x) x(p##4)
#define n5(p,x) n4(p,x) x(p##5)
#define n6(p,x) n5(p,x) x(p##6)
#define n7(p,x) n6(p,x) x(p##7)
#define n8(p,x) n7(p,x) x(p##8)
#define n9(p,x) n8(p,x) x(p##9)
#define n00(f,p,a,x) n##a(pad(p,f),x)
#define n10(f,p,a,x) n00(f,p,9,x) x(p##10) n##a(p##1,x)
#define n20(f,p,a,x) n10(f,p,9,x) x(p##20) n##a(p##2,x)
#define n30(f,p,a,x) n20(f,p,9,x) x(p##30) n##a(p##3,x)
#define n40(f,p,a,x) n30(f,p,9,x) x(p##40) n##a(p##4,x)
#define n50(f,p,a,x) n40(f,p,9,x) x(p##50) n##a(p##5,x)
#define n60(f,p,a,x) n50(f,p,9,x) x(p##60) n##a(p##6,x)
#define n70(f,p,a,x) n60(f,p,9,x) x(p##70) n##a(p##7,x)
#define n80(f,p,a,x) n70(f,p,9,x) x(p##80) n##a(p##8,x)
#define n90(f,p,a,x) n80(f,p,9,x) x(p##90) n##a(p##9,x)
#define n000(f,p,a,b,x) n##a##0(f,pad(p,f),b,x)
#define n100(f,p,a,b,x) n000(f,p,9,9,x) x(p##100) n##a##0(1,p##1,b,x)
#define n200(f,p,a,b,x) n100(f,p,9,9,x) x(p##200) n##a##0(1,p##2,b,x)
#define n300(f,p,a,b,x) n200(f,p,9,9,x) x(p##300) n##a##0(1,p##3,b,x)
#define n400(f,p,a,b,x) n300(f,p,9,9,x) x(p##400) n##a##0(1,p##4,b,x)
#define n500(f,p,a,b,x) n400(f,p,9,9,x) x(p##500) n##a##0(1,p##5,b,x)
#define n600(f,p,a,b,x) n500(f,p,9,9,x) x(p##600) n##a##0(1,p##6,b,x)
#define n700(f,p,a,b,x) n600(f,p,9,9,x) x(p##700) n##a##0(1,p##7,b,x)
#define n800(f,p,a,b,x) n700(f,p,9,9,x) x(p##800) n##a##0(1,p##8,b,x)
#define n900(f,p,a,b,x) n800(f,p,9,9,x) x(p##900) n##a##0(1,p##9,b,x)
#define n0000(f,p,a,b,c,x) n##a##00(f,pad(p,f),b,c,x)
#define n1000(f,p,a,b,c,x) n0000(f,p,9,9,9,x) x(p##1000) n##a##00(1,p##1,b,c,x)
#define n2000(f,p,a,b,c,x) n1000(f,p,9,9,9,x) x(p##2000) n##a##00(1,p##2,b,c,x)
#define n3000(f,p,a,b,c,x) n2000(f,p,9,9,9,x) x(p##3000) n##a##00(1,p##3,b,c,x)
#define n4000(f,p,a,b,c,x) n3000(f,p,9,9,9,x) x(p##4000) n##a##00(1,p##4,b,c,x)
#define n5000(f,p,a,b,c,x) n4000(f,p,9,9,9,x) x(p##5000) n##a##00(1,p##5,b,c,x)
#define n6000(f,p,a,b,c,x) n5000(f,p,9,9,9,x) x(p##6000) n##a##00(1,p##6,b,c,x)
#define n7000(f,p,a,b,c,x) n6000(f,p,9,9,9,x) x(p##7000) n##a##00(1,p##7,b,c,x)
#define n8000(f,p,a,b,c,x) n7000(f,p,9,9,9,x) x(p##8000) n##a##00(1,p##8,b,c,x)
#define n9000(f,p,a,b,c,x) n8000(f,p,9,9,9,x) x(p##9000) n##a##00(1,p##9,b,c,x)
#define n00000(f,p,a,b,c,d,x) n##a##000(f,pad(p,f),b,c,d,x)
#define n10000(f,p,a,b,c,d,x) n00000(f,p,9,9,9,9,x) x(p##10000) n##a##000(1,p##1,b,c,d,x)
#define n20000(f,p,a,b,c,d,x) n10000(f,p,9,9,9,9,x) x(p##20000) n##a##000(1,p##2,b,c,d,x)
#define n30000(f,p,a,b,c,d,x) n20000(f,p,9,9,9,9,x) x(p##30000) n##a##000(1,p##3,b,c,d,x)
#define n40000(f,p,a,b,c,d,x) n30000(f,p,9,9,9,9,x) x(p##40000) n##a##000(1,p##4,b,c,d,x)
#define n50000(f,p,a,b,c,d,x) n40000(f,p,9,9,9,9,x) x(p##50000) n##a##000(1,p##5,b,c,d,x)
#define n60000(f,p,a,b,c,d,x) n50000(f,p,9,9,9,9,x) x(p##60000) n##a##000(1,p##6,b,c,d,x)
#define n70000(f,p,a,b,c,d,x) n60000(f,p,9,9,9,9,x) x(p##70000) n##a##000(1,p##7,b,c,d,x)
#define n80000(f,p,a,b,c,d,x) n70000(f,p,9,9,9,9,x) x(p##80000) n##a##000(1,p##8,b,c,d,x)
#define n90000(f,p,a,b,c,d,x) n80000(f,p,9,9,9,9,x) x(p##90000) n##a##000(1,p##9,b,c,d,x)
#define cycle5(c1,c2,c3,c4,c5,x) n##c1##0000(0,,c2,c3,c4,c5,x)
#define cycle4(c1,c2,c3,c4,x) n##c1##000(0,,c2,c3,c4,x)
#define cycle3(c1,c2,c3,x) n##c1##00(0,,c2,c3,x)
#define cycle2(c1,c2,x) n##c1##0(0,,c2,x)
#define cycle1(c1,x) n##c1(,x)
#define concat(a,b,c) a##b##c
#define ck(arg) a[concat(,arg,-1)]++;
#define SIZEOF(x) (sizeof(x) / sizeof((x)[0]))
void check5(void)
{
int i, a[32769];
for (i = 0; i < SIZEOF(a); i++) a[i]=0;
cycle5(3,2,7,6,9,ck);
for (i = 0; i < SIZEOF(a); i++) if (a[i] != 1) printf("5: [%d] = %d\n", i+1, a[i]);
}
Here's an abuse of the rules that would get it done legally. Write your own C preprocessor. Make it interpret some #pragma directives the way you want.
I found this scheme useful when the compiler got cranky and wouldn't unroll certain loops for me
#define REPEAT20(x) { x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;x;}
REPEAT20( val = pleaseconverge(val) );
But IMHO, if you need something much more complicated than that, then you should write your own pre-preprocessor. Your pre-preprocessor could for instance generate an appropriate header file for you, and it is easy enough to include this step in a Makefile to have everything compile smoothly by a single command. I've done it.