C Pre-processing: Chaining defines together - c

I'm trying to concatenate multiple symbols together based on an if statement but have looked on SO and was unable to find something that worked without needing arguments passed into my last macro.
Essentially I'm trying to do this
#define COMMS_WD_PORT 1
#define COMMS_WD_TXRX CAN_TX
#if COMMS_WD_TXRX == CAN_TX
#define COMMS_WD_REG (uint32_t*)canREG#COMMS_WD_PORT##->TIOC
#else
#define COMMS_WD_REG (uint32_t*)canREG#COMMS_WD_PORT##->RIOC
#endif
Output I'd like
If COMMS_WD_TXRX == CAN_TX
expand COMMS_WD_REG to (uint32_t*)canREG1->TIOC
If COMMS_WD_TXRX == CAN_RX
expand COMMS_WD_REG to (uint32_t*)canREG1->RIOC
What I actually get
If COMMS_WD_TXRX == CAN_TX
COMMS_WD_REG expands to (uint32_t*)canREG#1->TIOC
If COMMS_WD_TXRX == CAN_RX
COMMS_WD_REG expands to (uint32_t*)canREG#1->RIOC
I'm quite stuck on the use of ## vs # and how to chain all of these together properly. I've looked at the gcc pre-processor guide but it didn't have examples that were close to what I'm trying to do.
Edit: My goal is to write to a specific bit in the COMMS_WD_REG register so if there's a better way to achieve the effect I want please let me know
Edit 2: I've found that
#define COMMS_WD_REG() (uint32_t*)canREG#COMMS_WD_PORT##->TIOC
COMMS_WD_REG() expands to canREG1->TIOC
Which is the output I want, but then I get an error "expected a macro parameter name" at COMMS_WD_PORT

The key piece here is that you want to paste together the token canREG with the token 1 that came from the expansion of COMMS_WD_PORT. Since the tokens pasted with ## are not normally subject to macro expansion, you need double indirection as explained in C: Expand Macro With Token Pasting.
Stealing ouah's example, we can do the following, with an auxiliary CANREG macro to simplify things a little bit:
#define COMMS_WD_PORT 1
#define COMMS_WD_TXRX CAN_TX
#define CAT(x, y) CAT_(x, y)
#define CAT_(x, y) x ## y
#define CANREG CAT(canREG, COMMS_WD_PORT)
#if COMMS_WD_TXRX == CAN_TX
#define COMMS_WD_REG (uint32_t*)CANREG->TIOC
#else
#define COMMS_WD_REG (uint32_t*)CANREG->RIOC
#endif
Now COMMS_WD_REG expands to (uint32_t*)canREG1->TIOC as desired. Try it on godbolt.

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

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

C "#define" function name generation

I have concrete_impl.h (as is):
#ifdef TUPLE_ITERATOR_WITH_INDEX
#define TUPLE_ITERATOR TUPLE_ITERATOR_NO_INDEX
#define iterate_tuple_fname iterate_tuple_id
#else
#define TUPLE_ITERATOR TUPLE_ITERATOR_INDEX
#define iterate_tuple_fname iterate_tuple
#endif
#undef iterate_tuple_fname_back
#define iterate_tuple_fname_back iterate_tuple_fname##_back
static void iterate_tuple_fname() // ok
{
}
static void iterate_tuple_fname_back() // redefinition error
{
}
And concrete.h (as is):
#ifndef CONCRETE_H
#define CONCRETE_H
#define TUPLE_ITERATOR_WITH_INDEX
#include "concrete_impl.h"
#undef TUPLE_ITERATOR_WITH_INDEX
#include "concrete_impl.h"
#endif // CONCRETE_H
What I want to get - is 4 functions:
iterate_tuple
iterate_tuple_id
iterate_tuple_back
iterate_tuple_id_back
But on "_back" functions I have redefinition error. Why?
iterate_tuple_fname##_back is nothing else than iterate_tuple_fname_back. To have iterate_tuple_fname replaced by its macro replacement list, you'll need a helper macro:
#define CONCAT(a, b) a ## b
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)
UPDATE: Sorry, have forgotten all about C after several years of C# programming.
It actually needs double run through helper macros:
#define CONCAT1(a, b) a ## b
#define CONCAT(a, b) CONCAT1(a, b)
#define iterate_tuple_fname_back CONCAT(iterate_tuple_fname, _back)
Apparently you misunderstand how the ## operator works.
If the preprocessing token adjacent to the ## operator is a parameter of the current macro, then this parameter is recursively analyzed for further replacement first, and the result of that replacement substituted into the result.
If the preprocessing token adjacent to the ## operator is not a parameter of the current macro, then recursive analysis and replacement of that token does not take place. The token is simply concatenated with the other token.
Later, once all parameters are substituted and all concatenations are joined, the entire result is rescanned again for further replacements. But then it is already be too late for your example.
In your case you defined this macro
#define iterate_tuple_fname_back iterate_tuple_fname##_back
Since iterate_tuple_fname is not a parameter of this macro, no early replacement occurs for iterate_tuple_fname. The whole thing is immediately concatenated into iterate_tuple_fname_back and only after that it is rescanned. But rescan finds nothing to replace there, so iterate_tuple_fname_back is the final result.
If you want the preprocessor to replace the left-hand side of the ## operator (which was your intent apparently), you absolutely have to use a macro parameter on the left-hand side, as in
#define ITF_back(prefix) prefix##_back
and then you can use this macro as
ITF_back(iterate_tuple_fname)
Now the rescan and recursive replacement inside iterate_tuple_fname will occur early, before the concatenation with the _back part. I.e. it will work as you wanted it to.

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.

Resources