Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why #define TRUE (1==1) in a C boolean macro instead of simply as 1?

Tags:

c

precompiler

This approach will use the actual boolean type (and resolve to true and false) if the compiler supports it. (specifically, C++)

However, it would be better to check whether C++ is in use (via the __cplusplus macro) and actually use true and false.

In a C compiler, this is equivalent to 0 and 1.
(note that removing the parentheses will break that due to order of operations)


The answer is portability. The numeric values of TRUE and FALSE aren't important. What is important is that a statement like if (1 < 2) evaluates to if (TRUE) and a statement like if (1 > 2) evaluates to if (FALSE).

Granted, in C, (1 < 2) evaluates to 1 and (1 > 2) evaluates to 0, so as others have said, there's no practical difference as far as the compiler is concerned. But by letting the compiler define TRUE and FALSE according to its own rules, you're making their meanings explicit to programmers, and you're guaranteeing consistency within your program and any other library (assuming the other library follows C standards ... you'd be amazed).


Some History
Some BASICs defined FALSE as 0 and TRUE as -1. Like many modern languages, they interpreted any non-zero value as TRUE, but they evaluated boolean expressions that were true as -1. Their NOT operation was implemented by adding 1 and flipping the sign, because it was efficient to do it that way. So 'NOT x' became -(x+1). A side effect of this is that a value like 5 evaluates to TRUE, but NOT 5 evaluates to -6, which is also TRUE! Finding this sort of bug is not fun.

Best Practices
Given the de facto rules that zero is interpreted as FALSE and any non-zero value is interpreted as TRUE, you should never compare boolean-looking expressions to TRUE or FALSE. Examples:

if (thisValue == FALSE)  // Don't do this!
if (thatValue == TRUE)   // Or this!
if (otherValue != TRUE)  // Whatever you do, don't do this!

Why? Because many programmers use the shortcut of treating ints as bools. They aren't the same, but compilers generally allow it. So, for example, it's perfectly legal to write

if (strcmp(yourString, myString) == TRUE)  // Wrong!!!

That looks legitimate, and the compiler will happily accept it, but it probably doesn't do what you'd want. That's because the return value of strcmp() is

      0 if yourString == myString
    <0 if yourString < myString
    >0 if yourString > myString

So the line above returns TRUE only when yourString > myString.

The right way to do this is either

// Valid, but still treats int as bool.
if (strcmp(yourString, myString))

or

// Better: lingustically clear, compiler will optimize.
if (strcmp(yourString, myString) != 0)

Similarly:

if (someBoolValue == FALSE)     // Redundant.
if (!someBoolValue)             // Better.
return (x > 0) ? TRUE : FALSE;  // You're fired.
return (x > 0);                 // Simpler, clearer, correct.
if (ptr == NULL)                // Perfect: compares pointers.
if (!ptr)                       // Sleazy, but short and valid.
if (ptr == FALSE)               // Whatisthisidonteven.

You'll often find some of these "bad examples" in production code, and many experienced programmers swear by them: they work, some are shorter than their (pedantically?) correct alternatives, and the idioms are almost universally recognized. But consider: the "right" versions are no less efficient, they're guaranteed to be portable, they'll pass even the strictest linters, and even new programmers will understand them.

Isn't that worth it?


The (1 == 1) trick is useful for defining TRUE in a way that is transparent to C, yet provides better typing in C++. The same code can be interpreted as C or C++ if you are writing in a dialect called "Clean C" (which compiles either as C or C++) or if you are writing API header files that can be used by C or C++ programmers.

In C translation units, 1 == 1 has exactly the same meaning as 1; and 1 == 0 has the same meaning as 0. However, in the C++ translation units, 1 == 1 has type bool. So the TRUE macro defined that way integrates better into C++.

An example of how it integrates better is that for instance if function foo has overloads for int and for bool, then foo(TRUE) will choose the bool overload. If TRUE is just defined as 1, then it won't work nicely in the C++. foo(TRUE) will want the int overload.

Of course, C99 introduced bool, true, and false and these can be used in header files that work with C99 and with C.

However:

  • this practice of defining TRUE and FALSE as (0==0) and (1==0) predates C99.
  • there are still good reasons to stay away from C99 and work with C90.

If you're working in a mixed C and C++ project, and don't want C99, define the lower-case true, false and bool instead.

#ifndef __cplusplus
typedef int bool;
#define true (0==0)
#define false (!true)
#endif

That being said, the 0==0 trick was (is?) used by some programmers even in code that was never intended to interoperate with C++ in any way. That doesn't buy anything and suggests that the programmer has a misunderstanding of how booleans work in C.


In case the C++ explanation wasn't clear, here is a test program:

#include <cstdio>

void foo(bool x)
{
   std::puts("bool");  
}

void foo(int x)
{
   std::puts("int");  
}

int main()
{
   foo(1 == 1);
   foo(1);
   return 0;
}

The output:

bool
int

As to the question from the comments of how are overloaded C++ functions relevant to mixed C and C++ programming. These just illustrate a type difference. A valid reason for wanting a true constant to be bool when compiled as C++ is for clean diagnostics. At its highest warning levels, a C++ compiler might warn us about a conversion if we pass an integer as a bool parameter. One reason for writing in Clean C is not only that our code is more portable (since it is understood by C++ compilers, not only C compilers), but we can benefit from the diagnostic opinions of C++ compilers.


#define TRUE (1==1)
#define FALSE (!TRUE)

is equivalent to

#define TRUE  1
#define FALSE 0

in C.

The result of the relational operators is 0 or 1. 1==1 is guaranteed to be evaluated to 1 and !(1==1) is guaranteed to be evaluated to 0.

There is absolutely no reason to use the first form. Note that the first form is however not less efficient as on nearly all compilers a constant expression is evaluated at compile time rather than at run-time. This is allowed according to this rule:

(C99, 6.6p2) "A constant expression can be evaluated during translation rather than runtime, and accordingly may be used in any place that a constant may be."

PC-Lint will even issue a message (506, constant value boolean) if you don't use a literal for TRUE and FALSE macros:

For C, TRUE should be defined to be 1. However, other languages use quantities other than 1 so some programmers feel that !0 is playing it safe.

Also in C99, the stdbool.h definitions for boolean macros true and false directly use literals:

#define true   1
#define false  0

Aside from C++ (already mentioned), another benefit is for static analysis tools. The compiler will do away with any inefficiencies, but a static analyser can use its own abstract types to distinguish between comparison results and other integer types, so it knows implicitly that TRUE must be the result of a comparison and should not be assumed to be compatible with an integer.

Obviously C says that they are compatible, but you may choose to prohibit deliberate use of that feature to help highlight bugs -- for example, where somebody might have confuse & and &&, or they've bungled their operator precedence.