#define N 1
#define A(N) #N
#define S_A A(N)
#define B_(N) #N
#define B(N) B_(N)
#define S_B B(N)
#include <stdio.h>
int main(void) {
puts(S_A);
puts(S_B);
}
outputs N and 1 instead of two 1s.
Why is the extra indirection making a difference?
It works different because the macro expansion of N only happens on the "use" of N. So S_A exands to A(N), which is expanded to #N. In S_B it is expanded to B(N), which is expanded to _B(1), and then #1. Why? Well, how would you do something like:
#define COMBINE(A, B) A##B
#define foo 1
#define bar 2
int COMBINE(foo, bar) = 34;
so that it generates int foobar = 34;, and not the illegal int 12 = 34;.
Did you intend to use a ## operator for token pasting?
puts(S_A); //Gets expanded into puts(A(N)) --> puts(#N)
and
puts(S_B); //Gets expanded into puts(B(N)) --> puts(_B(1)) --> puts(#1)
Without affecting your macros much, if you intend to print 1,1 both the times, you could Use the macros this way:
#define N "1" //instead of 1
#define A(N) N //instead of #N
#define B_(N) N //instead of #N
Related
I'm trying to define a preprocessor macro that in turn selects the right macro depending on the value of an argument.
#define BIT_8(n) n, "is lower or equal than 8"
#define BIT_N(n) n, "is greater than 8"
#define BIT(n) ?????
int main() {
printf("%d %s", BIT(9));
return 0;
}
BIT(n) should expand to:
BIT_8(n) if n≤8
BIT_N(n) if n>8
Any way to achieve this?
Unless you want very clumsy code, you can't do that. The preprocessor has no idea about the value of the argument passed in. It's just doing string replacement and that's all.
That being said, they are crazy guys implementing BIT_x for all x in [0 to 63].
This is very ugly and would fail is used with an argument set at 64.
A clean solution is to use a function instead:
const char * bit_msg(unsigned int b)
{
if (b > 8) return "is greater than 8";
const char * bits[] = {
"is 0 and lower than 8",
"is 1 and lower than 8",
"is 2 and lower than 8",
"is 3 and lower than 8",
"is 4 and lower than 8",
"is 5 and lower than 8",
"is 6 and lower than 8",
"is 7 and lower than 8",
"is 8",
};
return bits[b];
}
#define BIT(X) X, bit_msg(X)
[...]
printf("%d %s", BIT(9));
Because you've tagged the question with C++ and to follow #Romen you could achieve similar result using constexpr that, if possible, will be computed by the compiler at compile time, resulting in code that's as efficient as a macro.
In the example above, you'll just need to replace the signature with constexpr const char * bit_msg(unsigned int b) and the compiler might even skip the function and write (the equivalent of) printf("%d %s", 9, "is greater than 8").
The challenge is that the pre-processor doesn't know math. You can solve this problem by implementing the math you need, but it gets UGLY. For example, here's working pre-processor code for what you want to do:
#include <stdio.h>
#define BIT_8(n) n, "is lower or equal than 8"
#define BIT_N(n) n, "is greater than 8"
// Identify values less than 8; make the second argument 8
#define LT_8_0 ~,8
#define LT_8_1 ~,8
#define LT_8_2 ~,8
#define LT_8_3 ~,8
#define LT_8_4 ~,8
#define LT_8_5 ~,8
#define LT_8_6 ~,8
#define LT_8_7 ~,8
#define LT_8_8 ~,8
// Helper macros. Delays let arguments be processed before the macros is run.
#define MERGE(A, B) A ## B
#define MERGE_DELAY(A, B) MERGE(A,B)
#define ARG2(A,B,...) B
#define ARG2_DELAY(A,B,...) ARG2(A,B,__VA_ARGS__)
// Return 8 or N depending if n <= 8...
#define LT_8(n) ARG2_DELAY( MERGE(LT_8_, n), N,~ )
#define BIT(n) MERGE_DELAY(BIT_, LT_8(n))(n)
int main() {
printf("%d %s\n", BIT(9));
return 0;
}
Note that the LT_8 macro works by taking the second of a series of arguments. We default that second argument to N, but if we recognize the input number to be 8 or less, we insert a new second argument of 8.
you could do this
#include <stdio.h>
#define BIT_8(n) printf("%d is lower than or equal to 8 \n" , n)
#define BIT_N(n) printf("%d is greater than 8 \n" , n)
#define BIT(n) ((n <= 8) ? (BIT_8(n)) : (BIT_N(n)))
int main() {
BIT(7);
BIT(8);
BIT(9);
return 0;
}
I am trying to use Boost.Preprocessor to do some compile-time work. I want to index a table using values that are computed in other macros. When I try I get the following error: "concatenation with '(' in macro 'BOOST_PP_BOOL_I' does not create a valid token."
This is the simplest code that produces the issue.
#define MY_TABLE (0, (1, BOOST_PP_NIL))
#define MY_INDEX_FUNCTION(x) (x)
void func() {
int y = BOOST_PP_LIST_AT(MY_TABLE, MY_INDEX_FUNCTION(0));
}
It is pretty easy to determine that removing the parens in MY_INDEX_FUNCTION resolves the issue in this case. My actual code uses a much more complex function to calculate the table index in a much larger table.
Is there something that I can do or change that would fix this such that the parens and more complex macros don't cause problems?
The second parameter of BOOST_PP_LIST_AT takes an index/integer. It works with tricky preprocessor hacks under the hood. The parameter(expanded) should be exactly an integer-literal, not an integer inside parenthesis. The MY_INDEX_FUNCTION should be changed, so that the parameter passed to the BOOST_PP_LIST_AT is literally an integer-literal:
#define MY_INDEX_FUNCTION(x) x
The macro does not work with arithmetic expressions, this will not work:
#define MY_INDEX_FUNCTION(x) (x+1)
NOR
#define MY_INDEX_FUNCTION(x) x+1
But you can do this with
#define MY_INDEX_FUNCTION(x) MY_INDEX_FUNCTION_ ## x
#define MY_INDEX_FUNCTION_0 1
#define MY_INDEX_FUNCTION_1 2
#define MY_INDEX_FUNCTION_2 3
//...
This macro definitions can be created by a (python-)script
def my_index_function(x):
# insert the behavior of the macro here
return x+1
MACRO_NAME = "MY_INDEX_FUNCTION"
INDEX_MAX = 255
for x in range(INDEX_MAX):
print("#define %s_%i %i" % (
MACRO_NAME,
x,
my_index_function(x),
))
print("#define %s(x) %s_ ## x" % (
MACRO_NAME,
MACRO_NAME,
))
#include <iostream>
using namespace std;
#ifndef R
#define N1 10
#ifndef R
#define N2 11
#endif
#endif
int main(){
cout << N2 << endl;
}
From my understanding if R is not defined then N1 will be 10.
And second case where again R is defined again it should not be able to define N2 as 11, because R is already defined. I am just confused about it, And one Can please help to understand the point I have missed.
Let's walk through the code:
#ifndef R
R hasn't been defined yet, so step into the branch:
#define N1 10
N1 becomes 10
#ifndef R
R still hasn't been defined yet, so step into nested branch
#define N2 11
N2 is assigned to 11
#endif
Ends the nested branch
#endif
Ends the primary branch
So in the end R was never defined, so we assign N2 successfully.
You need to explicitly #define R or use -DR in the compiler line to define R, it won't get defined for you within a ifndef R branch.
The second #ifndef is redundant the way you currently have it organized. I'll write this out in a clearer pseudo code
IF R IS NOT DEFINED
SET N1 = 10
IF R IS NOT DEFINED
SET N2 = 11
END IF
END IF
This can be more simply
IF R IS NOT DEFINED
SET N1 = 10
SET N2 = 11
END IF
or in C/C++ preprocessor notation
#ifndef R
#define N1 10
#define N2 11
#endif
I'm learning C, but I do not understand this:
#define square(x) x*x
a = square(2+3) //a = 11
When this is run, why does a end up being 11?
It expands to 2+3*2+3, which is equivalent to 2+(3*2)+3. Use parentheses to fix it:
#define square(x) ((x)*(x))
Now try it with square(x++) and you'll run into more problems (undefined behavior). Avoid doing this as a macro if you can.
square(2+3) expands to 2+3*2+3 which is equivalent to 2+(3*2)+3 [* has higher precedence than +]
On gcc you can use -E option to see what your preprocessor generates
C:\Users\SUPER USER>type a.c
#define square(x) x*x
int main()
{
a = square(2+3); //a = 11
}
C:\Users\SUPER USER>gcc -E a.c
# 1 "a.c"
# 1 "<built-in>"
# 1 "<command-line>"
# 1 "a.c"
int main()
{
a = 2+3*2+3;
}
Remedy
Try this
#define square(x) ((x)*(x))
Try:
#define square(x) ((x)*(x))
Because 2 + 3 is substituted literally in the expression x * x, it becomes 2 + 3 * 2 + 3, and the * operator has a higher precedence so you don't get the expected result.
Always enclose macro arguments and the whole expression in parentheses to avoid this:
#define SQUARE(x) ((x) * (x))
Also note that any expression you pass will be evaluated twice, and that can be undesired if the expression has a side effect such as an assignment, or a function call. In these cases it is better to use an inline function.
think about what you get when the macro is expanded. The c preprocessor will expand this as
a = 2 + 3 * 2 + 3
You need to correctly define your macro. Always enclose the macro variable in parenthesis. This would give you the expected result.
#define square(x) ((x)*(x))
The macro expansion would be this:
a = ((2 + 3) * (2 + 3))
Why won't this work?
0. #define CONCAT(x, y) x ## y
1.
2. #define VAR_LINE(x) \
3. int CONCAT(_anonymous, __LINE__) = x
4.
5. #define VAR_LINE2(x) \
6. int _anonymous ## x = 1
7.
8. int main()
9. {
10. VAR_LINE(1);
11. VAR_LINE(1);
12. VAR_LINE(1);
13. VAR_LINE2(__LINE__);
14. }
The result from the above macro expansion
int _anonymous__LINE__ = 1;
int _anonymous__LINE__ = 1;
int _anonymous__LINE__ = 1;
int _anonymous13 = 1;
It would be convenient if I didn't have to write that __LINE__ macro as an argument.
I'm thinking the problem is pretty clear. I want to be able to generate anonymous variables so that this macro doesn't fail with redefinition error when declaring several variables within the same scope. My idea was to use the predefined __LINE__ macro because no variable will ever be declared on the same line like this. But the macro expansion troubles me, can you help?
Update: Correct answer
Thanks to Luc Touraille. However, there was a tiny problem with the suggested solution. There has to be whitespace between the operands and the ## operator (apparently the standard says otherwise but the the PS3 flavoured GCC would not expand the macro properly if there were no whitespace between the operator and operands).
#define _CONCAT(x,y) x ## y
#define CONCAT(x,y) _CONCAT(x,y)
The VAR_LINE macro now yields:
int _anonymous10 = 1;
int _anonymous11 = 1;
int _anonymous12 = 1;
This has been verified to work under Win32 (Visual Studio 2008), XBOX360 (Xenon) and PS3.
You need to add a level of indirection so that __LINE__ will be expanded:
#define _CONCAT_(x,y) x ## y
#define CONCAT(x,y) _CONCAT_(x,y)
#define VAR_LINE(x) int CONCAT(_anonymous, __LINE__) = x