C-preprocessor: iteratively expand macro to comma-separated list - c-preprocessor
Using Paul Fultz II's solution in the post C-preprocessor recursive macro, I'd like to expand an unlimited number of parenthesized macro arguments, e.g.
#define MY_CHAIN (alpha) (beta) (gamma)
into a comma-separated list which can be passed to a variadic macro, e.g.
CHAIN_COMMA(MY_CHAIN) // alpha, beta, gamma
I'm able to expand into braces [alpha] [beta] [gamma] and delimit the list with everything I've tried except a comma, alpha :: beta :: gamma in the example below.
Here is my full (compiling) code:
#include <iostream>
using namespace std;
// unrelated macro utilities
#define SEE(expression) cout << #expression ": " << STR(expression) << endl;
#define CMD(function, ...) function(__VA_ARGS__)
#define STR(s) CMD(STR_, s)
#define STR_(s) #s
// concatenation
#define CAT(x, y) CAT_(x, y)
#define CAT_(x,y) x ## y // error from CHAIN_COMMA: passed 4 arguments
// surround each chain element with square brackets []
#define CHAIN_BRACE(chain) CAT(CHAIN_BRACE_1 chain, _END)
#define CHAIN_BRACE_1(x) [x] CHAIN_BRACE_2
#define CHAIN_BRACE_2(x) [x] CHAIN_BRACE_1
#define CHAIN_BRACE_1_END
#define CHAIN_BRACE_2_END
// separate each chain element with the scope operator ::
#define CHAIN_SCOPE(chain) CAT(CHAIN_SCOPE_0 chain, _END)
#define CHAIN_SCOPE_0(x) x CHAIN_SCOPE_1
#define CHAIN_SCOPE_1(x) :: x CHAIN_SCOPE_2
#define CHAIN_SCOPE_2(x) :: x CHAIN_SCOPE_1
#define CHAIN_SCOPE_0_END
#define CHAIN_SCOPE_1_END
#define CHAIN_SCOPE_2_END
// trouble here: can't separate chain elements with commas
#define CHAIN_COMMA(chain) CAT(CHAIN_COMMA_0 chain, _END) // error
#define CHAIN_COMMA_0(x) x CHAIN_COMMA_1
#define CHAIN_COMMA_1(x) , x CHAIN_COMMA_2
#define CHAIN_COMMA_2(x) , x CHAIN_COMMA_1
#define CHAIN_COMMA_0_END
#define CHAIN_COMMA_1_END
#define CHAIN_COMMA_2_END
// define a custom chain and save various forms of it
#define MY_CHAIN (alpha) (beta) (gamma)
#define MY_BRACES CHAIN_BRACE(MY_CHAIN) // [alpha] [beta] [gamma]
#define MY_SCOPES CHAIN_SCOPE(MY_CHAIN) // alpha :: beta :: gamma
#define MY_COMMAS CHAIN_COMMA(MY_CHAIN) // alpha , beta , gamma
int main() {
SEE(MY_CHAIN);
SEE(MY_BRACES);
SEE(MY_SCOPES);
// SEE(MY_COMMAS); // error: macro "CAT_" passed 4 arguments, but takes just 2
return 0;
}
This outputs:
MY_CHAIN: (alpha) (beta) (gamma)
MY_BRACES: [alpha] [beta] [gamma]
MY_SCOPES: alpha :: beta :: gamma
I tried parenthesizing the comma-separated list but CAT won't append ) to _END. Any clever ideas to expand into alpha, beta, gamma?
As the comma is both important to your output and is a syntactic element, you need to make a substitute comma for outputting.
#define COMMA() ,
We will also need some deferring functions so that COMMA isn't evaluated immediately.
#define EMPTY()
#define DEFER(id) id EMPTY()
Now we can redefine your two macros into
#define CHAIN_COMMA_1(x) DEFER(COMMA)() x CHAIN_COMMA_2
#define CHAIN_COMMA_2(x) DEFER(COMMA)() x CHAIN_COMMA_1
However, your SEE macro also doesn't like the commas that are placed, and so will error for having too many parameters passed.
You can see that the macro is performing correctly by looking at the output of the preprocessor with the -E option.
Related
C Preprocessor: concatenate macro call with token
I'm trying to concatenate a macro call with a token to create a new one, for instance: #define TEST(X) X ## _TEST #define CONCAT(X) TEST(X) ## _CONCAT CONCAT(OK); Then I check the output with gcc -E; I would want to get OK_TEST_CONCAT; but instead I get an error: error: pasting ")" and "_CONCAT" does not give a valid preprocessing token If I remove ## I get no error but the output is OK_TEST _CONCAT; This is a minimal example, so the easiest here would be to combine everything in a single macro, but know that it's impossible for me to get rid of the first call to TEST. Is there a way to remove that space? Thanks EDIT: Ok so from the confusion maybe my example was a little too minimal, that's my fault. Here is a more plausible use case: I want all the prototypes in a certain header to be prefixed by the PREFIX defined in that header. proto.h: #define EXPAND(X) EXPAND_HELPER(X) #define EXPAND_HELPER(X) X #define PROTO(NAME) PREFIX ## NAME other.h: #include <proto.h> #define PREFIX other int PROTO(test)(int a, int b); ... What I want is all the prototypes in other.h to have this form: int other_test(int a, int b);. But as it is they have this form: int PREFIX_test(int a, int b);. After googling I found that I needed to force PREFIX to rescan, so I tried this: #define PROTO(NAME) EXPAND(PREFIX) ## NAME which prompted my question. Now if I look at #Lundin's answer, I can adapt it to give what I want: Solution: #define PROTO(NAME) PROTO_HELPER(PREFIX, NAME) #define PROTO_HELPER(PREFIX, NAME) PROTO_EXPAND(PREFIX, NAME) #define PROTO_EXPAND(PREFIX, NAME) PREFIX ## NAME Thanks!
All preprocessor tokens must be expanded before a function-like macro using ## or # is called. Because ## or # is applied before macro expansion. In your case TEST(X) only expands X into TEST(OK) and then the preprocessor attempts to paste TEST(OK) with _CONCAT which won't work. For each attempt to concatenate tokens, you must first expand all macros before ##, which is done by extra helper macros that force a rescanning/replacement. The contrived solution given #define TEST(X) X ## _TEST would be this: #define CONCAT(X) EXPAND_HELPER(TEST(X)) // expands TEST(X) to TEST(OK) --> #define EXPAND_HELPER(X) CONCAT_HELPER(X, _CONCAT) // expands TEST(OK) to OK_TEST --> #define CONCAT_HELPER(X,Y) X ## Y That is: // NOTE: contrived solution, avoid #define TEST(X) X ## _TEST #define CONCAT_HELPER(X,Y) X ## Y #define EXPAND_HELPER(X) CONCAT_HELPER(X, _CONCAT) #define CONCAT(X) EXPAND_HELPER(TEST(X)) ... int CONCAT(OK) = 1; // becomes int OK_TEST_CONCAT = 1; A much simpler solution would be: #define CONCAT(X) X ## _TEST ## _CONCAT
Generate non-stringified text literal macro at build time
Background In a separate question of mine, I created a function-like-macro that allows me to concatenate a user-supplied text literal to create a macro name, i.e.: /****************************************************************************** * coconut.h ******************************************************************************/ #define COCONUT_FX_REGISTER (100) #define COCONUT_BASE_REGISTER (101) /******************************************************************************* * pineapple.h ******************************************************************************/ #define PINEAPPLE_FX_REGISTER (200) #define PINEAPPLE_BASE_REGISTER (201) /******************************************************************************* * test.c. ******************************************************************************/ #include <stdio.h> #include "translation.h" #include "coconut.h" #include "pineapple.h" int main(void) { int i = getTranslation(FX_REGISTER, COCONUT); printf("Translation:%d.\n", i); return 0; } /******************************************************************************* * translation.h ******************************************************************************/ #define getTranslation(x, y) y ## _ ## x Goal I would like to extend this logic so that I can use a macro for a default value to pass to getTranslation, i.e.: #define XFRM(x) #x #define XFRM2(x) XFRM(x) #define DEFAULT_PRODUCT XFRM2(COCONUT) int main(void) { int i = getTranslation(FX_REGISTER, DEFAULT_PRODUCT); printf("Translation:%d.\n", i); return 0; } Problem However, I can't seem to get DEFAULT_PRODUCT to be converted to a non-string text literal. Build Errors main.c: In function ‘main’: main.c:14:35: error: ‘DEFAULT_PRODUCT_FX_REGISTER’ undeclared (first use in this function) printf("%d\n", getTranslation(FX_REGISTER, DEFAULT_PRODUCT)); ^ translation.h:33:25: note: in definition of macro ‘getTranslation’ #define getTranslation(x, y) y ## _ ## x ^ main.c:14:35: note: each undeclared identifier is reported only once for each function it appears in printf("%d\n", getTranslation(FX_REGISTER, DEFAULT_PRODUCT)); ^ translation.h:33:25: note: in definition of macro ‘getTranslation’ #define getTranslation(x, y) y ## _ ## x Question How can I create a DEFAULT_PRODUCT macro that resolves to a non-string text literal so that I can create a "default" value to use with getTranslation? This is using GCC set to C99 pedantic.
Sounds like an XY problem. It seems that macro concatenations are processed simultaneous to macro literal expansions, so I'm afraid there's no way to create a DEFAULT_PRODUCT macro that gets expanded before getTranslation. My proposal: Create another macro function getDefaultTranslation(x) and you'll easily achieve what you want. // You may want to add appropriate comments // so code reviewers know what this is doing. #define getDefaultTranslation(x) COCONUT ## x Regarding this question, macro expansion is done layer-by-layer, and at the same layer concatenation has a higher precedence , so adding another layer should work. See ringø's answer below.
You need to add an indirection in order to let the preprocessor expand the macros before doing the concatenation #define CONCAT(a, b) a ## _ ## b #define getTranslation(x, y) CONCAT(x,y) #define XFRM(x) x #define XFRM2(x) XFRM(x) #define DEFAULT_PRODUCT XFRM2(COCONUT) Note that XFRM has its # removed (off x), otherwise the " gives an invalid preprocessing token. This way you get int i = FX_REGISTER_COCONUT;
Macro concatenation inside other macro concatenation in c
I have the following macros: #define __IR( x ) ICU.IR[ IR ## x ].BIT.IR #define _IR( x ) __IR( x ) #define IR( x , y ) _IR( _ ## x ## _ ## y ) I use it in this way: IR(SCI7, RXI7) = 0; That expands to: ICU.IR[ IR_SCI7_RXI7 ].BIT.IR = 0 Instead of use SCI7 and RXI7 I'd like to use sci(channel) and rxi(channel). So I've tried to create the following macros: #define _sci(x) SCI ## x #define sci(x) _sci(x) #define _rxi(x) RXI ## x #define rxi(x) _rxi(x) #define channel 7 And then: IR(sci(channel), rxi(channel)) = 0; But it didn't work. The compiler returns me: Error[Pe017]: expected a "]" I've been trying to with other manners also but without success. What I'm doing wrong?
The whole macro is expanded with the literal sub-epressions and the macros in the result expression are expanded after that. So you could write: #define __IR(x ) ICU.IR[ IR ## x ].BIT.IR #define _IR(x, y) __IR(_ ## x ## _ ## y) #define IR(x, y) _IR(x, y) #define _sci(x) SCI ## x #define sci(x) _sci(x) #define _rxi(x) RXI ## x #define rxi(x) _rxi(x) #define channel 7 IR(sci(channel), rxi(channel)) = 0; (The only thing I've really changed is the definition of _IR. On anther note, macro identifiers and symbold beginning with underscores are reserved for the compiler, so you might want to rename your secondary macros.)
You're making the mistake of believing a macro function is like a function call whereas it actually involves text substitution on source code. In rough terms, the preprocessor will expand IR(sci(channel), rxi(channel)) = 0 to _IR( _sci(channel)_rxi(channel)) = 0 and expands that to ICU.IR[IR_sci(channel)_rxi(channel)].BIT.IR = 0. The result of all that is then compiled as C. That bit between the square brackets is not a valid C expression at all. The compiler gets confused on that, hence the cryptic error message. That's the explanation for the problem. The solution? You haven't given enough information to help anyone suggest one.
C Macro building with defines
I am having trouble getting this macro expanison right #define foo Hello #ifdef foo #define wrapper(x) foo ## x #else #define wrapper(x) boo ## x #endif calling: wrapper(_world) I would like the result of Hello_world however, the macro is treating the "foo" define as a literal, and thus giving foo_world Can someone point out my mistake? Thanks
I would recommend gnu-cpp-manual which clearly explains how macros are expanded. Macro arguments are completely macro-expanded before they are substituted into a macro body, unless they(macro arguments) are stringified or pasted with other tokens (by the macro function that is directly applied to). For example: If an argument is stringified or concatenated, the prescan does not occur. #define AFTERX(x) X_ ## x #define XAFTERX(x) AFTERX(x) #define TABLESIZE 1024 #define BUFSIZE TABLESIZE AFTERX(BUFSIZE) => X_BUFSIZE: since AFTERX is to concatenate argument with prefix, its argument is not expanded, remaining BUFSIZE. XAFTERX(BUFSIZE) => X_1024: XAFTERX does not do concatenation directly, so BUFSIZE will be expanded first. Generally, arguments are scanned twice to expand macro called in them. --- edit --- So the better practice is: (code from QEMU source) #ifndef glue #define xglue(x, y) x ## y #define glue(x, y) xglue(x, y) #define stringify(s) tostring(s) #define tostring(s) #s #endif glue(x,y) will concatenate x and y with both already expanded.
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.