Consider the following C++ code:
#include <bits/stdc++.h>
using namespace std;
string TRUE = "true";
string FALSE = "false";
#define TRUE FALSE
#define FALSE TRUE
int main()
{
cout << TRUE << endl;
cout << FALSE << endl;
}
Compiled using GCC 4.9.2, the above code outputs:
true
false
What is the logic behind the produced output? I expected "false\ntrue\n" or even "false\nfalse\n", but I cannot find the reasoning behind this actual output.
How does the pair of #defines work in this case?
Macros and its types in C/C++ A macro is a piece of code in a program that is replaced by the value of the macro. Macro is defined by #define directive. Whenever a macro name is encountered by the compiler, it replaces the name with the definition of the macro.
To invoke a macro that takes arguments, you write the name of the macro followed by a list of actual arguments in parentheses, separated by commas. The invocation of the macro need not be restricted to a single logical line—it can cross as many lines in the source file as you wish.
A macro is a fragment of code that is given a name. You can define a macro in C using the #define preprocessor directive.
To create a macro function, simply define a macro with a parameter that has whatever name you like, such as my_val . For example, one macro defined in the standard libraries is abs , which returns the absolute value of its parameter.
This is described in [cpp.rescan]/1-2:
16.3.4 Rescanning and further replacement
- After all parameters in the replacement list have been substituted and
#
and##
processing has taken place, all placemarker preprocessing tokens are removed. Then the resulting preprocessing token sequence is rescanned, along with all subsequent preprocessing tokens of the source file, for more macro names to replace.- If the name of the macro being replaced is found during this scan of the replacement list (not including the rest of the source file's preprocessing tokens), it is not replaced. Furthermore, if any nested replacements encounter the name of the macro being replaced, it is not replaced. These nonreplaced macro name preprocessing tokens are no longer available for further replacement even if they are later (re)examined in contexts in which that macro name preprocessing token would otherwise have been replaced.
(Emphasis mine)
So: When TRUE
is encountered in the code, it is replaced with FALSE
. The sequence is rescanned, FALSE
is replaced with TRUE
. The sequence is rescanned, TRUE
is found but no longer eligible for replacement, and so it stays. The same applies for the expansion of FALSE
(with swapped identifiers).
Macros cannot be recursive: if a macro directly on indirectly expands to include its own name, that second occurrence will not be expanded any more. So in your case, the following expansions happen:
Input:
cout << TRUE << endl;
TRUE
is a macro, it's expanded:
cout << FALSE << endl;
Expanded text re-scanned for macros, FALSE
is found and expanded:
cout << TRUE << endl;
Expanded text re-scanned for macros, TRUE
is found; but it was already expanded once, so nothing happens and it stays as TRUE
for subsequent compilation (which then finds the global variable).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With