Is it possible to process math calculation before stringify a macro? - c
I look through a lot of examples online about macro stringification but can't find something similar.
I currently have the definitions as below.
#define PIN_A (0+1)
#define PIN_B (0+2)
#define PIN_C (0+3)
#define str(x) #x
#define xstr(x) str(x)
#define PIN_DEF(x) { #x, xstr(PIN_ ## x) }
The output of
PIN_DEF(A)
will become
{ "A", "(0+1)" }
However, what I really need is
{ "A", "1" }
Is it even possible? :/
Yes, it's possible.
#include <boost/preprocessor/arithmetic.hpp>
#define PIN_A BOOST_PP_ADD(0,1)
#define PIN_B BOOST_PP_ADD(0,2)
#define PIN_C BOOST_PP_ADD(0,3)
#define str(x) #x
#define xstr(x) str(x)
#define PIN_DEF(x) { #x, xstr(PIN_##x) }
PIN_DEF(A)
Keep in mind boost preprocessor's arithmetic macros saturate at 256.
Caveats
The preprocessor can also evaluate expressions, but the only means of doing so is to invoke preprocessor conditional directives (such as #if <expression>/#elif <expression>). You can make a useful expression evaluator out of this, with usage limitations, but it doesn't seem to fit this use case. Macro math needs to be adopted to macro usage (and essentially implemented from scratch), so operations must be implemented in terms of macro calls.
Related
Using macro statement in macro function in C
Using #ifdef <macro> <statement> #endif allows one to have verbose messages displayed only during development and is quite handy. I wonder if something like the code below is possible, becoming even shorter: // pseudo-code: #define IN_DEV #define DEBUG_ONLY(statement) (#ifdef IN_DEV (statement) #endif) int main(void) { DEBUG_ONLY(printf("hello from debug mode\n");) //... } This would only cost me a very readable one-liner which can be turned on or off. Is something like this / close to this possible?
You could change the meaning of DEBUG_ONLY dependent on if IN_DEV is defined: // pseudo-code: #ifdef IN_DEV #define DEBUG_ONLY(statement) {statement} #else #define DEBUG_ONLY(statement) // Nothing #endif int main(void) { DEBUG_ONLY(printf("hello from debug mode\n");) //... } Running example: Link
It doesn't make much sense to pass whole expressions as parameters to macros. That is both dangerous and unmaintainable. Worse yet, it's taking us down the obfuscation road of "lets invent our own private macro language instead of using readable C that anyone can understand". That's a terrible idea even for debugging purposes. The more sensible approach would be a function-like printing macro which only prints something in debug build. #ifdef INDEV #define DEBUG_PRINT(...) printf(__VA_ARGS__) #else #define DEBUG_PRINT(...) #endif int main(void) { DEBUG_PRINT("hello from debug mode\n"); } Optionally this macro can be narrowed down to only accept strings and be made more type safe (C17 only): #ifdef INDEV #define DEBUG_PRINT(str) _Generic((str), char*: puts(str)) #else #define DEBUG_PRINT(str) _Generic((str), char*: (void)0) #endif
That is not possible. You cannot use #if inside a macro definition. What you can do is this: #define IN_DEV #ifdef #define DEBUG_ONLY(statement) (statement) #else #define DEBUG_ONLY(statement) #endif int main(void) { DEBUG_ONLY(printf("hello from debug mode\n");) //... } This is also switchable with only a single macro IN_DEV.
How do I concatenate two string macros in C?
I am trying to implement VERSION macro for my program, that is to be changed under certain circumstances. macro VERSION is defined via Makefile (git info is put there) and is a string. Now I have a set of #define'd switches and I want VERSION to reflect which of them are on. This looks now like the follows (main.h): #define COMPLEX_DEPOSITION // This is switch. later in code it is used in #ifdef...#endif construction. #ifdef COMPLEX_DEPOSITION #define CD "_COMP_DEP" // this is the string I want to put in the end of VERSION #define VERSION_ VERSION CD #undef VERSION // this is to suppress 'macro redefinition' warning #define VERSION VERSION_ #undef VERSION_ #endif Well, I get a lot of errors, most of which make me think that C preprocessor works with lines in file in random order:( Later I have an even more complex thing that is intended to make VERSION -> VERSION_WLT_GAP_2 #define WIRESLIFETIMES #ifdef WIRESLIFETIMES #define GAP 2 #define VERSION_ (VERSION ## "_WLT_GAP_" ## #GAP) #define VERSION VERSION_ #undef VERSION_ #endif and I got no idea what to do and if this is even possible
String literals concatenate naturally when placed next to each other "foo" "bar" is the same as "foobar". As for the second example, you probably want: #define CAT_(A,B) A##B #define CAT(A,B) CAT_(A,B) #define GAP 2 #define VERSION CAT(VERSION_WLT_GAP_ , GAP) VERSION //expands to VERSION_WLT_GAP_2 I recommend playing with gcc -E/clang -E a bit, to learn how macros work, before trying to compose anything complex with them.
Well, the answer seems to be the following: // https://stackoverflow.com/questions/5256313/c-c-macro-string-concatenation // Concatenate preprocessor tokens A and B without expanding macro definitions (however, if invoked from a macro, macro arguments are expanded). #define PPCAT_NX(A, B) A ## B // Concatenate preprocessor tokens A and B after macro-expanding them. #define PPCAT(A, B) PPCAT_NX(A, B) // Turn A into a string literal without expanding macro definitions (however, if invoked from a macro, macro arguments are expanded). #define STRINGIZE_NX(A) #A // Turn A into a string literal after macro-expanding it. #define STR(A) STRINGIZE_NX(A) #define COMPLEX_DEPOSITION #ifdef COMPLEX_DEPOSITION #define CD "_COMPDEP" #else #define CD "" #endif #define WIRESLIFETIMES #ifdef WIRESLIFETIMES #define GAP 2 #define WLT STR(PPCAT(_WLT:G, GAP)) #define DISABLE_METROPOLIS #else #define WLT "" #endif #define VERSION VERSIONX CD WLT which produces V008.1-11-g68a9c89cb4-dirty_COMPDEP_WLT:G2 and I am happy with it. Must be noted that I changed -DVERSION=... to -DVERSIONX=... inside Makefile
Stringify first level macro expansion C
Is it possible to stringify this C macro: #define GPIO_INT_PIN (GPIO_PORT_D|GPIO_PIN_IRQ_RISING|GPIO_PIN5) using something like MY_STRINGFY(GPIO_INT_PIN) to get "(GPIO_PORT_D|GPIO_PIN_IRQ_RISING|GPIO_PIN5)" ?
Yes it is possible. Read about stringizing in GCC cpp documentation. #define STRINGIFY(It) #It #define MY_STRINGIFY(It) STRINGIFY(It) I corrected my answer thanks to Wojtek Surowka's one then use MY_STRINGIFY(GPIO_PORT_D|GPIO_PIN_IRQ_RISING|GPIO_PIN5) which would work much better if you use an enum to define the constants, e.g. enum Gpio_stuff_en { GPIO_PORT_D=5, GPIO_PIN_IRQ_RISING=17, GPIO_PIN5=23 }; Of course that won't work as you want if you need GPIO_PORT_D to be a macro, .e.g. because it expands to some non-constant-literal expression (like a variable, or an access to a field of some global structure, etc....) As a counter-example: #define FOO 1 #define BAR 2 #define STRINGIFY(s) #s #define MY_STRINGIFY(s) STRINGIFY(s) MY_STRINGIFY(FOO|BAR) is expanded to "1|2" not to "FOO|BAR", if your remove the two #define-s for FOO and for BAR and replace them with enum { FOO=1, BAR=2 }; you really get the expansion "FOO|BAR" as you want. Check with gcc -C -E ... Also: enum {FOO=1, BAR=2}; #define FOOORBAR (FOO|BAR) #define STRINGIFY(s) #s #define MY_STRINGIFY(s) STRINGIFY(s) MY_STRINGIFY(FOOORBAR) is expanded as "(FOO|BAR)" . But if you use #define for FOO and for BAR you get the "(1|2)" expansion. Maybe you could add in your own header, after including the external header defining GPIO_PORT_D etc... as a literal constants, something like : enum {en_GPIO_PORT_D= GPIO_PORT_D, en_GPIO_PIN_IRQ_RISING= GPIO_PIN_IRQ_RISING, en_GPIO_PIN5= GPIO_PIN5}; #undef GPIO_PORT_D #undef GPIO_PIN_IRQ_RISING #undef GPIO_PIN5 #define GPIO_PORT_D en_GPIO_PORT_D #define GPIO_PIN_IRQ_RISING en_GPIO_PIN_IRQ_RISING #define GPIO_PIN5 en_GPIO_PIN5 and then you'll get more readable stringified constants (but not exactly what you dream of).
If you have such two definitions #define STRINGIFY(s) #s #define MY_STRINGIFY(s) STRINGIFY(s) MY_STRINGIFY does what you want - expands its argument and adds quotes after.
y combinator and the C preprocessor
As far as I know y combinator is useful if you want to write a recursive function without using recursion explicitly. The C preprocessor does not support recursion. Can we implement the y combinator in C preprocessor in order to support recursion? Thanks.
In fact this is completely possible, please see my project CSP Git Repo, this is a LISP interpreter COMPLETELY implemented on C macro preprocessor, and of course you can implement Y combinator on it. Hope you to and some tests/example if you are interested in it. Here is the most relevant part. (from csp.h) It successfully implements closure and lambda, which gives support for implementing fixed point combinators. #define EVAL_e(x) x #define _be(y) y) #define ZIP(x) _n() (x,_be #define _PAIR(x,y) _e( __PAIR(x,y)) #define __PAIR(x,y) _E COND((NULL SAFE_CDR(x)((SAFE_CAR(x) SAFE_CAR(y))))((T)((SAFE_CAR (x) SAFE_CAR (y)) _e(_PAIR2(_e SAFE_CDR(x),_e SAFE_CDR(y)))))) #define _PAIR2(x,y) _E COND((NULL SAFE_CDR(x)((SAFE_CAR(x) SAFE_CAR(y))))((T)((SAFE_CAR (x) SAFE_CAR (y)) _e(_PAIR3(_e SAFE_CDR(x),_e SAFE_CDR(y)))))) #define _PAIR3(x,y) _E COND((NULL SAFE_CDR(x)((SAFE_CAR(x) SAFE_CAR(y))))((T)((SAFE_CAR (x) SAFE_CAR (y)) _e(_PAIR4(_e SAFE_CDR(x),_e SAFE_CDR(y)))))) #define _PAIR4(x,y) _E COND((NULL SAFE_CDR(x)((SAFE_CAR(x) SAFE_CAR(y))))((T)((SAFE_CAR (x) SAFE_CAR (y)) _e(DELAY_INT_54(__PAIR_R) ()(SAFE_CDR(x) SAFE_CDR(y)))))) #define __PAIR_R() _$pair #define TEST_R() TEST #define TEST(x) test #define _PAIR_e(x) x #define _$pair(x) _PAIR_e(_PAIR ZIP x) #define PAIR_EVAL(...) PAIR_EVAL2(PAIR_EVAL2(PAIR_EVAL2(__VA_ARGS__))) #define PAIR_EVAL2(...) PAIR_EVAL3(PAIR_EVAL3(PAIR_EVAL3(__VA_ARGS__))) #define PAIR_EVAL3(...) PAIR_EVAL4(PAIR_EVAL4(PAIR_EVAL4(__VA_ARGS__))) #define PAIR_EVAL4(...) PAIR_EVAL_E(PAIR_EVAL_E(PAIR_EVAL_E(__VA_ARGS__))) #define PAIR_EVAL_E(...) __VA_ARGS__ #define $pair(x) PAIR_EVAL(_$pair(x)) #define $zipped_evlis_R() $zipped_evlis #define EVLIS_e_R() EVLIS_e #define EVLIS_e(x) x #define _EVLIS_ZIP(...) _n() (__VA_ARGS__,_BE #define _BE(...) __VA_ARGS__) #define _EVLIS_R() _EVLIS #define _EVLIS_E(...) __VA_ARGS__ #define _EVLIS_N(...) #define _EVLIS_B _EVLIS_E (_EVLIS_N,_EVLIS_E(_EVLIS_N,_EVLIS_N)) #define ___EVLIS(a,b,k,...) k($zipped_eval((b),(a)) DELAY_INT_2(_EVLIS_R)()(a)) #define __EVLIS(a,b,...) ___EVLIS(a,b,__VA_ARGS__ _EVLIS_E) #define _EVLIS_EVAL_E(...) __VA_ARGS__ #define _EVLIS_EVAL_5(...) _EVLIS_EVAL_E(_EVLIS_EVAL_E(_EVLIS_EVAL_E(__VA_ARGS__))) #define _EVLIS_EVAL_4(...) _EVLIS_EVAL_5(_EVLIS_EVAL_5(_EVLIS_EVAL_5(__VA_ARGS__))) #define _EVLIS_EVAL_3(...) _EVLIS_EVAL_4(_EVLIS_EVAL_4(_EVLIS_EVAL_4(__VA_ARGS__))) #define _EVLIS_EVAL_2(...) _EVLIS_EVAL_3(_EVLIS_EVAL_3(_EVLIS_EVAL_3(__VA_ARGS__))) #define _EVLIS_EVAL(...) _EVLIS_EVAL_2(_EVLIS_EVAL_2(_EVLIS_EVAL_2(__VA_ARGS__))) #define _EVLIS(x) __EVLIS _EVLIS_ZIP(x) #define $zipped_evlis(x,y) _EVLIS_EVAL(_EVLIS y x (_EVLIS_B)) #define $zipped_eval_R() $zipped_eval #define $zipped_eval(e,a) /**sth irrelevant**/ ($eq(SAFE_CAR SAFE_CAR e (lambda))\ (DELAY_INT_26(EVAL_e_R)() DELAY_INT_23($zipped_eval_R)()(\ EVAL_e(EVAL_e(EVAL_e(EVAL_e(SAFE_CAR SAFE_CDR SAFE_CDR SAFE_CAR e)))),\ EVAL_e(APPEND DELAY_INT_13($pair_R)()(EVAL_e(EVAL_e(EVAL_e(SAFE_CAR SAFE_CDR SAFE_CAR e)))\ (DELAY_INT_19($zipped_evlis_R)()(EVAL_e(_e EVAL_e(SAFE_CDR e)), a)))a)))\ /**end of eval recursion**/ #define $pair_R() $pair #define EVAL_e_R() EVAL_e #define $eval_E(...) __VA_ARGS__ #define $eval_expand5(...) $eval_E($eval_E($eval_E(__VA_ARGS__))) #define $eval_expand4(...) $eval_expand5($eval_expand5($eval_expand5(__VA_ARGS__))) #define $eval_expand3(...) $eval_expand4($eval_expand4($eval_expand4(__VA_ARGS__))) #define $eval_expand2(...) $eval_expand3($eval_expand3($eval_expand3(__VA_ARGS__))) #define $eval_expand(...) $eval_expand2($eval_expand2($eval_expand2(__VA_ARGS__))) #define $zeval(x,y) $eval_expand($zipped_eval(x,y))
Y combinator is a higher-order function and it needs a higher-order function support in the language to implement an explicit recursion substitution. Therefore, for particular tasks this can be done in Scheme, SML and other functional languages. Let's talk about C preprocessor later, but what about C itself? It could be possible to use higher order functions in C as we can pass function references as function arguments and return them to emulate higher-order functions. However, the lack of closures support in the language does not allow to implement Y combinator. As preprocessor is even more restrictive that C, there is no way to implement Y combinator which is based on lambda calculus concepts. The application of Y combinator can be achieved only in functional programming languages with higher-order functions full support. C preprocessor is very straightforward as it does only string substitution in a text. I would not try to apply any concepts from lambda calculus and functional programming to it.
How to write a while loop with the C preprocessor?
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.