This blog post explains how to iterate over the variable number of arguments of a C preprocessor macro, and call another macro for each argument.
Let's assume we want automate generating the following strings:
const char import0[] = ""; const char import1[] = "import os\n"; const char import2[] = "import os\nimport os.path\n"; const char import3[] = "import os\nimport os.path\nimport sys\n"; const char import4[] = "import os\nimport os.path\nimport sys\nimport re\n"; const char import5[] = "import os\nimport os.path\nimport sys\nimport re\n" "import select\n"; const char import6[] = "import os\nimport os.path\nimport sys\nimport re\n" "import select\nimport struct\n";
A simple option is to create a macro which uses stringification:
#define IMPORT(n) "import " #n "\n" const char import0[] = ""; const char import1[] = IMPORT(os); const char import2[] = IMPORT(os) IMPORT(os.path); const char import3[] = IMPORT(os) IMPORT(os.path) IMPORT(sys); const char import4[] = IMPORT(os) IMPORT(os.path) IMPORT(sys) IMPORT(re); const char import5[] = IMPORT(os) IMPORT(os.path) IMPORT(sys) IMPORT(re) IMPORT(select); const char import6[] = IMPORT(os) IMPORT(os.path) IMPORT(sys) IMPORT(re) IMPORT(select) IMPORT(struct);
Would it be possible to create a variadic macro which would call IMPORT for all its arguments? We want the following to work:
const char import0[] = IMPORT_ALL(); const char import1[] = IMPORT_ALL(os); const char import2[] = IMPORT_ALL(os, os.path); const char import3[] = IMPORT_ALL(os, os.path, sys); const char import4[] = IMPORT_ALL(os, os.path, sys, re); const char import5[] = IMPORT_ALL(os, os.path, sys, re, select); const char import6[] = IMPORT_ALL(os, os.path, sys, re, select, struct);
Indeed, it's possible, define the IMPORT_ALL macro like this:
#define IMPORT_ALL(...) "" APPLY_ALL(IMPORT, __VA_ARGS__)
The tricky part is defining the APPLY_ALL macro. Here is a possible implementation which works with gcc and clang, and it supports up to 6 arguments. (It's easy to increase the number of supported arguments.)
#define APPLY0(t, dummy) #define APPLY1(t, a) t(a) #define APPLY2(t, a, b) t(a) t(b) #define APPLY3(t, a, b, c) t(a) t(b) t(c) #define APPLY4(t, a, b, c, d) t(a) t(b) t(c) t(d) #define APPLY5(t, a, b, c, d, e) t(a) t(b) t(c) t(d) t(e) #define APPLY6(t, a, b, c, d, e, f) t(a) t(b) t(c) t(d) t(e) t(f) #define NUM_ARGS_H1(dummy, x6, x5, x4, x3, x2, x1, x0, ...) x0 #define NUM_ARGS(...) NUM_ARGS_H1(dummy, ##__VA_ARGS__, 6, 5, 4, 3, 2, 1, 0) #define APPLY_ALL_H3(t, n, ...) APPLY##n(t, __VA_ARGS__) #define APPLY_ALL_H2(t, n, ...) APPLY_ALL_H3(t, n, __VA_ARGS__) #define APPLY_ALL(t, ...) APPLY_ALL_H2(t, NUM_ARGS(__VA_ARGS__), __VA_ARGS__) #define IMPORT_ALL(...) "" APPLY_ALL(IMPORT, __VA_ARGS__) #define IMPORT(n) "import " #n "\n" const char import0[] = IMPORT_ALL(); const char import1[] = IMPORT_ALL(os); const char import2[] = IMPORT_ALL(os, os.path); const char import3[] = IMPORT_ALL(os, os.path, sys); const char import4[] = IMPORT_ALL(os, os.path, sys, re); const char import5[] = IMPORT_ALL(os, os.path, sys, re, select); const char import6[] = IMPORT_ALL(os, os.path, sys, re, select, struct);
See http://stackoverflow.com/questions/2632300/looping-through-macro-varargs-values and http://stackoverflow.com/questions/824639/variadic-recursive-preprocessor-macros-is-it-possible for inspiration and a more detailed explanation on NUM_ARGS and C macros with a variable number of arguments.
No comments:
Post a Comment