A #define's replacement list containing no spaces can be mapped to integers (IDs):
#define ID_double 1
#define ID_float 2
#define ID_long_double 3
#define ID_(x) ID_##x
#define ID(x) ID_(x)
#define T double
T v;
int x = ID(T); /* 1 */
Now consider:
#define T long double
The code above won't compile:
<source>:3:25: error: 'ID_long' undeclared here (not in a function)
Question: is there a way to support spaces?
For example (somehow):
#define REPLACE_SPACES_TO_UNDERSCORES(x) ??
#define ID(x) ID_(REPLACE_SPACES_TO_UNDERSCORES(x))
#define T long double
T v;
int x = ID(T); /* 3 */
The same idea I had in Replace spaces with underscores in a macro? can also be used here, and the dictionary will be much more realistical in size. In the following code on the end, ID(T) is replaced by 3.
// dictionary
#define WORD_long long,
#define WORD_double double,
// ---------------------------------------------
// the classics
#define COMMA(...) ,
#define FIRST(a, ...) a
// apply function f for each argument recursively with tail
#define FOREACHTAIL_1(f,a) f(a,)
#define FOREACHTAIL_2(f,a,...) f(a,FOREACHTAIL_1(f,__VA_ARGS__))
#define FOREACHTAIL_3(f,a,...) f(a,FOREACHTAIL_2(f,__VA_ARGS__))
#define FOREACHTAIL_4(f,a,...) f(a,FOREACHTAIL_3(f,__VA_ARGS__))
#define FOREACHTAIL_N(_4,_3,_2,_1,N,...) \
FOREACHTAIL_##N
#define FOREACHTAIL(f,...) \
FOREACHTAIL_N(__VA_ARGS__,4,3,2,1)(f,__VA_ARGS__)
// if there are two arguments, expand to true. Otherwise false.
#define IFTWO_N(_0,_1,N,...) N
#define IFTWO(true, false, ...) IFTWO_N(__VA_ARGS__, true, false)
// If empty, expand to true, otherwise false.
// https://gustedt.wordpress.com/2010/06/08/detect-empty-macro-arguments/
#define IFEMPTY(true, false, ...) IFTWO(true, false, COMMA __VA_ARGS__ ())
// Join arguments with `_`.
#define JOIN_U(a, b) a##_##b
#define JOIN_TWO_IN(a,b) IFEMPTY(FIRST, JOIN_U, b)(a, b)
#define JOIN_TWO(a,b) JOIN_TWO_IN(a,b)
#define JOIN(...) FOREACHTAIL(JOIN_TWO, __VA_ARGS__)
// Append WORD_ to each argument and join arguments with spaces.
#define WORD_ /* the last one expands to empty */
#define WORDS_TWO(a, b) WORD_##a b
#define WORDS(...) FOREACHTAIL(WORDS_TWO, __VA_ARGS__)
#define REPLACE_SPACES_TO_UNDERSCORES(a) JOIN(WORDS(WORDS(WORDS(WORDS(WORDS(a))))))
// --------------------------------------------
#define ID_double 1
#define ID_float 2
#define ID_long_double 3
#define ID_IN2(x) ID_##x
#define ID_IN(x) ID_IN2(x)
#define ID(x) ID_IN(REPLACE_SPACES_TO_UNDERSCORES(x))
int main() {
#define T long double
T v;
int x = ID(T); /* 3 */
}
#include <stdio.h>
#define X 2
#define N_1_T 50
#define N_2_T 49
#define PRINT() printf("id: %d", N_ ## X ## _T)
int main(void)
{
PRINT();
return 0;
}
I want N_ ## X ## _T to be expanded to N_2_T when I have the Macro #define X 2. If I change the Macro definition of X to be #define X 1, N_ ## X ## _T should be expanded to N_1_T.
But I do not know how to do this. I have searched and read many pages, but I just do not get what I should do to achieve the desired result.
Please help, thank you.
To achieve what you want, the X macro must be expanded to the pre-processor token 2 before concatenation, so the macro containing the ## must get passed an expanded 2. It is very similar to this: Stringification - how does it work?
You can solve this with a number of helper macros that enforce rescanning of the pp tokens:
#include <stdio.h>
#define X 2
#define N_1_T 50
#define N_2_T 49
#define CONCAT(n) N_ ## n ## _T
#define GET_ID(n) CONCAT(n)
#define PRINT() printf("id: %d", GET_ID(X))
int main(void)
{
PRINT();
return 0;
}
Output:
id: 49
I ran this code in this compiler
#define CCc(n) CC_##n
#define CC(n) CCc(n)
#define CC_1 (1,2)
#define CC_2 (3,4)
#define CALL_FUNCTION(xy) Coord(xy)
#define YES 1
#define NO 0
int Coord(x, y){
if (x < 0.5 && y < 1.5){
return YES;
}
return NO;
}
int main()
{
for(int i = 1; i < 3; i++){
CALL_FUNCTION(CC(i));
}
return 0;
}
and got this error:
error: use of undeclared identifier 'CC_i'
Why does this error occur? And what is the right way to achieve this?
You cannot do run-time/variable evaluations in the pre-processor. It requires compile-time pre-processor tokens. So rather than trying to define a number of #define based on run-time values, you should gather all compile-time constants in one place.
A common way to do so is "X macros". In your case it might look like this:
#define CC_LIST \
/* n x y */ \
X(1, 1, 2) \
X(2, 3, 4) \
int main()
{
#define X(n,x,y) (void) Coord(x, y);
CC_LIST
#undef X
return 0;
}
This expands to (void) Coord(1,2); (void) Coord(3,4);, so it is a compile-time loop unrolling of sorts.
Alternatively, if you insist on having the "CC_N" macros because they are also needed for other purposes, you can do this:
#define CC_LIST \
/* n */ \
X(1) \
X(2) \
#define CC(n) CC_##n
#define CC_1 1,2
#define CC_2 3,4
#define CALL_FUNCTION(...) (void) Coord(__VA_ARGS__);
int main()
{
#define X(n) CALL_FUNCTION(CC(n))
CC_LIST
#undef X
return 0;
}
As you can tell, macro tricks like "X macros" are not easy to read and should be regarded as the last resort. Only use them when proper program re-design is not possible, for example during maintenance of existing code.
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.
I'm trying to use multiple macros in the definition of another macro, but seem to have problems concatenating them together. Here's a very simplified version of what I'm trying to do:
#include <stdio.h>
#define PICK_SET_A
#ifdef PICK_SET_A
#define SET A
#endif
#ifdef PICK_SET_B
#define SET B
#endif
#define ENABLE_VAR_1_A 1
#define ENABLE_VAR_2_A 1
#define ENABLE_VAR_1_B 0
#define ENABLE_VAR_2_B 0
#define MACRO_RESOLVE(var,set) ENABLE_VAR_##var##_##set
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
#define ENABLE_VAR_2 MACRO_RESOLVE(2, SET)
int main(int argc, char **argv) {
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
return 0;
}
I would expect the result to be 0.
However, I'm getting compile errors because the MACRO_RESOLVE macro isn't resolving the way I expect it to:
$ gcc -o asdf asdf.c
asdf.c:25:36: error: use of undeclared identifier 'ENABLE_VAR_1_SET'
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
^
asdf.c:20:26: note: expanded from macro 'ENABLE_VAR_1'
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
^
asdf.c:18:32: note: expanded from macro 'MACRO_RESOLVE'
#define MACRO_RESOLVE(var,set) ENABLE_VAR_##var##_##set
^
<scratch space>:229:1: note: expanded from here
ENABLE_VAR_1_SET
^
1 error generated.
So it looks like SET isn't getting expanded when I define ENABLE_VAR_1.
Since you are trying to build a macro name, you need to do enough intermediate expansions along the way for all tokens to expand. See it live here.
#include <stdio.h>
#define PICK_SET_A
#ifdef PICK_SET_A
#define SET A
#endif
#ifdef PICK_SET_B
#define SET B
#endif
#define ENABLE_VAR_1_A 1
#define ENABLE_VAR_2_A 1
#define ENABLE_VAR_1_B 0
#define ENABLE_VAR_2_B 0
#define MACRO_RESOLVE__(M) M
#define MACRO_RESOLVE_(V, S) MACRO_RESOLVE__(ENABLE_VAR_ ## V ##_## S)
#define MACRO_RESOLVE(var,set) MACRO_RESOLVE_(var, set)
#define ENABLE_VAR_1 MACRO_RESOLVE(1, SET)
#define ENABLE_VAR_2 MACRO_RESOLVE(2, SET)
int main(int argc, char **argv) {
fprintf(stdout, "VALUE: %d\n", ENABLE_VAR_1);
return 0;
}