Imagine I want to #define a macro such that it is equal to the current value of another macro (if such a concept exists).
For example:
#include "def_a.h" // defines macro A
#define B A
This defines B to be A. If A later changes definition (i.e., through a redefinition) the value of B also changes (because B expands to A at the point of use, which further expands to the new value of A).
What I'd like is some way to "bake in" the value of A into B so that B just expands to the value of A, not A itself.
For example:
#define A first
#define B BAKE_IN(A)
#undef A
#define A second
#define C BAKE_IN(A)
#undef A
#define A third
// here I want B to expand to first, and C to expand to second
Of course BAKE_IN is not a real thing, but I'm wondering if there is some way to achieve this effect.
Now, I didn't really say what should happen if A itself is defined in terms of other macros, but I'm OK both with "one level of expansion" (i.e., B gets the value of A is expanded, so further macros remain) and also "full expansion" (i.e., A is fully expanded, recursively, as it would be at a point of use).
Macros are never replaced in the body of a #define directive, so there is no way to define a macro as the current value of another macro, except for the limited case of macros whose value is a constant arithmetic expression.
In the latter case, you can use BOOST_PP_ASSIGN_SLOT from the Boost preprocessor library. (Although most of the Boost libraries are C++-specific, the Boost preprocessor library works for both C and C++, and has no dependency on any other Boost component.)
I don't think there is a clean solution. The closest thing that I found is to preserve "stringified" values within char arrays:
#include <stdio.h>
#define BAKE_IN(X, id) BAKE_IN_REAL(X ## _, X, id)
#define BAKE_IN_REAL(X, Y, id) static const char X ## id[] = #Y;
#define BAKE_OUT(X, id) X ## _ ## id
#define A first
BAKE_IN(A, 1)
#define B BAKE_OUT(A, 1)
#undef A
#define A second
BAKE_IN(A, 2)
#define C BAKE_OUT(A, 2)
#undef A
int main(void)
{
printf("%s\n", B); // prints "first"
printf("%s\n", C); // prints "second"
return 0;
}
The idea is that BAKE_IN macro declares object named as e.g. A_1, which holds the current expansion of A.
There are two major limitations:
Every pair of BAKE_IN and BAKE_OUT needs unique id
The expansion is only available in "stringified" form
Related
I would like to pass 2 arguments to a macro using another macro:
#define A_AND_B 5,1
#define ADD(a, b) a + b
int add_them(void)
{
int result = ADD(A_AND_B);
return result ;
}
I would hope that expands to
int result = 5 + 1;
and I get 6. Instead I get
Error 'ADD' undeclared (first use in this function)
Error macro "ADD" requires 2 arguments, but only 1 given
Is there a way around this?
As is often the case, you need an extra level of (macro) indirection:
#define A_AND_B 5,1
#define ADD(...) ADD_(__VA_ARGS__)
#define ADD_(a, b) a + b
int add_them(void)
{
int result = ADD(A_AND_B);
return result ;
}
ADD is defined as variadic so that it will work as either ADD(A_AND_B) or ADD(A, B).
This works because __VA_ARGS__ in the replacement body of ADD is replaced with the actual arguments before the replacement body is scanned for macros.
Per C 2018 6.10.3.1, a compiler first identifies the arguments for a function-like macro and then performs macro replacement on the arguments, followed by macro replacement for the function-like macro. This means that, in ADD(A_AND_B), the argument is identified as A_AND_B before it is replaced with 5,1. As the macro invocation has only this single argument and the macro is defined to have two parameters, an error is diagnosed.
Given your definition of ADD, there is no way to change this behavior in a compiler that conforms to the C standard.
You can instead use another macro to expand the arguments and apply the desired macro:
#define Apply(Macro, Arguments) Macro(Arguments)
then int result = Apply(ADD, A_AND_B); will work. That will identify ADD and A_AND_B as arguments to Apply. Then it will expand those, producing an unchanged ADD and 5,1. Then the macro replacement for Apply produces ADD(5,1). Then this is again processed for macro replacement, which replaces ADD(5,1) in the ordinary way.
Note that good practice is usually to define ADD as #define ADD(a, b) ((a) + (b)) to avoid unexpected interactions with other operators neighboring the use of the macro.
Below I change the value of the function that I call depending on the value of INPUT:
#include <stdio.h>
#define INPUT second
#if INPUT == first
#define FUNCTOCALL(X) first(X)
#elif INPUT == second
#define FUNCTOCALL(X) second(X)
#endif
void first(int x) {
printf("first %d\n", x);
}
void second(int x) {
printf("second %d\n", x);
}
int main() {
FUNCTOCALL(3);
return 0;
}
However, the output is first 3, even if INPUT is equal to second, as above. In fact, the first branch is always entered, regardless of the value of INPUT. I'm completely stumped by this - could someone explain what stupid mistake I'm making?
The c preprocessor only works on integer constant expressions in its conditionals.
If you give it tokens it can't expand (such as first or second where first and second aren't macros)
it'll treat them as 0 and 0 == 0 was true last time I used math. That's why the first branch is always taken.
6.10.1p4:
... After all replacements due to macro expansion and the defined
unary operator have been performed, all remaining identifiers
(including those lexically identical to keywords) are replaced with
the pp-number 0, and then each preprocessing token is converted into a
token. ...
You have no macros first and second defined. Be aware that the pre-processor is not aware of C or C++ function names!* In comparisons and calculations (e. g. #if value or #if 2*X == Y), macros not defined (not defined at all or undefined again) or defined without value evaluate to 0. So, as first and second are not defined, INPUT is defined without value, and the comparison in both #if expressions evaluates to 0 == 0...
However, if you did define the two macros as needed, they would collide with the C function names and the pre-processor would replace these with the macro values as you just defined them, most likely resulting in invalid code (e. g. functions named 1 and 2)...
You might try this instead:
#define INPUT SECOND
#define FIRST 1
#define SECOND 2
#if INPUT == FIRST
#define FUNCTOCALL(X) first(X)
#elif INPUT == SECOND
#define FUNCTOCALL(X) second(X)
#else
# error INPUT not defined
#endif
Note the difference in case, making the macro and the function name differ.
* To be more precise, the pre-processor is not aware of any C or C++ tokens, so it does not know about types like int, double, structs or classes, ... – all it knows is what you make it explicitly aware of with #define, everything else is just text it operates on and, if encountering some known text nodes, replacing them with whatever you defined.
I made the code snippet simpler to explain
// Example 1
#define sum2(a, b) (a + b)
#define sum3(a, b, c) (sum2(a, sum2(b, c)))
sum3(1, 2, 3) // will be expanded to ((1 + (2 + 3)))
// Example 2
#define score student_exam_score
#define print_score(student_exam_score) printf("%d\n", score)
#undef score
print_score(80); // will be expanded to printf("%d\n", score);
// but not printf("%d\n", 80); that I expect
The first one is intuitive, and that kinds of codes exists in several places such as finding the maximum or minimum number. However, I want to use that technique to make my code clean and easy to read, so I replace the some words in a macro with a shorter and more meaningful name.
AFAIK, C preprocessor runs only once per compilation unit and only performs string replacement, but why print_score cannot be expanded to printf("%d\n", 80);?
This is the replacement procedure I guess:
#define score student_exam_score
#define print_score(student_exam_score) printf("%d\n", score)
#undef score
print_score(80);
// -->
#define score student_exam_score // runs this first
#define print_score(student_exam_score) printf("%d\n", student_exam_score) // changed
#undef score
print_score(80);
// -->
#define score student_exam_score
#define print_score(student_exam_score) printf("%d\n", student_exam_score) // then this
#undef score
printf("%d\n", 80); // changed
It's a sequencing issue. First the macros are defined, and score is undefined before it is ever used. Then, when print_score is expanded, it first substitutes all instances of student_exam_score, of which there are none. It then rescans the result, looking for further macros to expand, but there are none since score has been undefined and is no longer available.
Even if you moved #undef score down below the reference to print_score, it still wouldn't work since parameter substitution only happens once (score would be expanded but student_exam_score would not).
Note that score is not substituted into the body of print_score at the time is it defined. Substitution only happens when the macro is instantiated, which is why #undef score results in the score macro having no effect whatsoever.
These examples will make it clearer. First, consider the following:
#define foo bar
#define baz(bar) (foo)
baz(123)
This is expanded as follows:
baz(123)
-> (foo)
-> (bar)
Expansion stops here. Parameter substitution was done before foo was expanded, and does not happen again.
Now consider the following:
#define foo bar
#define baz(bar) (foo)
#undef foo
baz(123)
This is expanded as follows:
baz(123)
-> (foo)
Expansion stops here because foo is no longer defined. Its earlier definition had no effect on the definition of baz, because macro substitution does not happen when macros are defined. It only happens when they are expanded.
Let's say I have already defined 9 macros from
ABC_1 to ABC_9
If there is another macro XYZ(num) whose objective is to call one of the ABC_{i} based on the value of num, what is a good way to do this? i.e. XYZ(num) should call/return ABC_num.
This is what the concatenation operator ## is for:
#define XYZ(num) ABC_ ## num
Arguments to macros that use concatenation (and are used with the operator) are evaluated differently, however (they aren't evaluated before being used with ##, to allow name-pasting, only in the rescan pass), so if the number is stored in a second macro (or the result of any kind of expansion, rather than a plain literal) you'll need another layer of evaluation:
#define XYZ(num) XYZ_(num)
#define XYZ_(num) ABC_ ## num
In the comments you say that num should be a variable, not a constant. The preprocessor builds compile-time expressions, not dynamic ones, so a macro isn't really going to be very useful here.
If you really wanted XYZ to have a macro definition, you could use something like this:
#define XYZ(num) ((int[]){ \
0, ABC_1, ABC_2, ABC_3, ABC_4, ABC_5, ABC_6, ABC_7, ABC_8, ABC_9 \
}[num])
Assuming ABC_{i} are defined as int values (at any rate they must all be the same type - this applies to any method of dynamically selecting one of them), this selects one with a dynamic num by building a temporary array and selecting from it.
This has no obvious advantages over a completely non-macro solution, though. (Even if you wanted to use macro metaprogramming to generate the list of names, you could still do that in a function or array definition.)
Yes, that's possible, using concatenation. For example:
#define FOO(x, y) BAR ##x(y)
#define BAR1(y) "hello " #y
#define BAR2(y) int y()
#define BAR3(y) return y
FOO(2, main)
{
puts(FOO(1, world));
FOO(3, 0);
}
This becomes:
int main()
{
puts("hello " "world");
return 0;
}
I want to know which macro gets replaced first in the following code
#define A 100
#define B 200
#define C(A,B) A+B
here when we use C, then evaluation will be from left to right or right to left. That is B gets the value first or A gets the value first
i gave this example just to make things look simple, may be i was wrong. the actual thing i want to ask is, if A and B also take arguments and have the scope of expansion, then which one would expand first
I'm not sure what you mean. There's never a point where you can "see" half a result of the preprocessor; the entire input file is preprocessed, then handed over to the compiler.
I think that the names for the macro arguments will never also be replaced as if they were stand-alone symbols.
I tried it, and this program:
#include <stdio.h>
#define A 100
#define B 200
#define C(A, B) A + B
int main(void) {
printf("A=%d\nB=%d\nC(1,2)=%d\n", A, B, C(1,2));
return 0;
}
prints
A=100
B=200
C(1,2)=3
So, C(1,2) expands to 1 + 2, the definitions of A and B don't matter.
Of course I must say that I find the above very bad practice, since it's quite confusing. Never use all-caps names for macro arguments, since macros and preprocessor symbols tend to use such names.