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

Why does it output "01"?

casperOne
  • 73,706
  • 19
  • 184
  • 253
hired777
  • 485
  • 3
  • 10
  • 24
    Seriously? You wrote that code? To define `true` to `false` and vice versa? Find the nearest shoe and beat yourself over the head with it repeatedly until you figure out what the problem is. – Cody Gray - on strike Mar 01 '12 at 19:56
  • 1
    I didn`t write this code (= I just want to understand – hired777 Mar 01 '12 at 19:59
  • 2
    It can probably be explained with a little-known, usually obscure (but very relevant in some cases) fact regard macro expandion, but when you start quoting the standard, you might as well short-circuit and state what Jerry Coffin already stated. As far as the ISO is concerned, the compiler might start a robot revolution and make the robots beat the author with the nearest shoe to make @CodyGray happy. –  Mar 01 '12 at 19:59
  • @hired777 What did you expect it to print and why? – Mr Lister Mar 01 '12 at 20:00
  • please check this thread: http://stackoverflow.com/questions/2726204/c-preprocessor-define-ing-a-keyword-is-it-standards-conforming – Karoly Horvath Mar 01 '12 at 20:03
  • 6
    @Griwes: Actually the OP has some point: at a superficial level (and at a deep religious prejudice) it seems *WTF question*, but it is the simplest sample (apart that fact he used keywords for macros, thus causing an UB, but can easily resolved with other symbols) of #define recursion. I know by experience the most of the programmers are even not aware of. And if required to try to figure it out, they just "escape" away. So that -when recoursing by mistake- are unable to recognize the problem. – Emilio Garavaglia Mar 01 '12 at 20:18

2 Answers2

13

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.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • Good explanation! But just one question, are you giving him ideas to write more code like above???? – noMAD Mar 01 '12 at 20:03
  • 5
    @noMAD: No, one should not ordinarily write code like this, but that doesn't mean that we should not explain why this code works the way it does. It is important to understand how your programming language works, even in the "silly" corners of the language that "nobody uses." For the record, I have written code exactly like this, in a unit test for an implementation of the C preprocessor I was working on for a while (admittedly, I have strange hobbies). – James McNellis Mar 02 '12 at 22:17
11

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.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    Why don't you just go and see through the ISO instead of asking for "link" to it? Anyway, "link to ISO" links to document, so it wouldn't give you anything new. – Griwes Mar 01 '12 at 19:58
  • I see through it, but i can`t find explanation – hired777 Mar 01 '12 at 19:59
  • 1
    Do we look like human interface to ISO standard or humanish index of it? – Griwes Mar 01 '12 at 20:00
  • 2
    @Griwes Given the amount of `language-lawyer` question having answers with perfectly attributes quotes from the standard, we do. –  Mar 01 '12 at 20:02
  • http://stackoverflow.com/questions/2726204/c-preprocessor-define-ing-a-keyword-is-it-standards-conforming – Karoly Horvath Mar 01 '12 at 20:05
  • Oh, could it be so simple? :-) The person who gave the accepted answer to the question linked by @yi_H may have thought too much about that question and completely missed the obvious answer in §2.11/1. – James McNellis Mar 01 '12 at 20:10
  • @JerryCoffin i understand that true\false is keywords. But, "..The identifiers shown in Table 4 are reserved for use as keywords.."(§2.12) - so true\false are _identifiers_ too. "# define identifier replacement-list new-line"(§6.3.1.9). – hired777 Mar 01 '12 at 20:21
  • @hired777: The fact that the grammar uses `identifier` doesn't mean "any possible identifier is allowed here", only that what goes there must be an identifier -- subject to other restrictions, such as those in §2.11/1. – Jerry Coffin Mar 01 '12 at 20:28
  • 1
    @JerryCoffin This is not an answer but a comment. Please expand it. – casperOne Mar 02 '12 at 21:55
  • @JerryCoffin Remember, not everyone who will come across this is as knowledgeable about as you or other members of the community are. That said, no one said it had to be the "why", but please provide *some* context. – casperOne Mar 02 '12 at 22:10
  • @JerryCoffin Your answer (which I agree is an answer and not a comment) would be better if you included that reference to §2.11, plus the citation that shows that keywords can't be pp-tokens. I'd do it, but I'm a C guy, I don't have the C++ standard on call. – Gilles 'SO- stop being evil' Mar 02 '12 at 22:21