Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the expected output when redefining true to false and vice versa?

#include <iostream>
#define true false
#define false true
int main() {
    std::cout << false << true;
}

Why does it output "01"?

like image 291
hired777 Avatar asked Mar 01 '12 19:03

hired777


2 Answers

As Jerry Coffin notes, you cannot define a macro with a name that is a keyword.

However, we could consider another, similar example, with well-defined behavior and the same result. Consider:

int TRUE = 1;
int FALSE = 0;

#define TRUE FALSE
#define FALSE TRUE

std::cout << FALSE << TRUE;

When you use FALSE, it is identified as the macro FALSE and is replaced by that macro's replacement list, which is the single token, TRUE. That replacement is then rescanned for further macros to replace.

The TRUE in the replacement is then identified as a macro and is replaced by its replacement list, which is the single token FALSE. That replacement is again rescanned.

If we continued on rescanning and replacing, we'd end up in an infinite loop, so the C (and C++) preprocessing specifications state that macro replacement never recurses within a replacement list.

Since replacement of FALSE in this final replacement list would result in recursion, macro replacement stops and we are left with FALSE, which is the name of an int with a value of 0.

like image 116
James McNellis Avatar answered Jan 02 '23 07:01

James McNellis


Any attempt at re-defining a reserved word gives undefined behavior.

Edit:

§2.11/1: "The identifiers shown in Table 3 are reserved for use as keywords." I won't try to reproduce all of Table 3, but it includes both false and true. It may be open to some question whether this is an absolute prohibition, though, since the same sentence adds: "(that is, they are unconditionally treated as keywords in phase 7)", which suggests that it's possible to re-define keywords this way, since the macros involved would be/are expanded before phase 7.

In this case, however, you've also included <iostream>, which brings another rule into play (§17.4.3.1.1): "A translation unit that includes a header shall not contain any macros that define names declared or defined in that header. Nor shall such a translation unit define macros for names lexically identical to keywords."

The wording here strongly suggests that there's an intent that if a translation unit didn't include any header, it would be free to re-define a keyword as you've done, but given the presence of the #include <iostream>, there's no question that you have undefined behavior.

Once you have undefined behavior, there really is no more to say about "why" anything happens -- at that point, the standard is very clear that any behavior is permissible.

like image 26
Jerry Coffin Avatar answered Jan 02 '23 08:01

Jerry Coffin