Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange result from mutual reference in C++ macro

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?

like image 634
fushar Avatar asked Mar 21 '15 13:03

fushar


People also ask

What is the data type of macro in C?

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.

How to invoke a macro in C?

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.

How to define a function as a macro in C?

A macro is a fragment of code that is given a name. You can define a macro in C using the #define preprocessor directive.

How do you write a macro function?

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.


2 Answers

This is described in [cpp.rescan]/1-2:

16.3.4 Rescanning and further replacement

  1. 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.
  2. 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).

like image 57
Wintermute Avatar answered Oct 03 '22 21:10

Wintermute


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).

like image 22
Angew is no longer proud of SO Avatar answered Oct 03 '22 21:10

Angew is no longer proud of SO