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 int
s as bool
s. 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:
TRUE
and FALSE
as (0==0)
and (1==0)
predates C99.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 be1
. 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.
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