94

As far as I can see, there are three ways to use Booleans in C:

  1. with the bool type, from <stdbool.h> then using true and false
  2. defining using preprocessor #define FALSE 0 ... #define TRUE !(FALSE)
  3. Just to use constants directly, i.e. 1 and 0

Are there other methods I missed? What are the pros and cons of the different methods?

I suppose the fastest would be number 3, 2 is more easily readable still (although bitwise negation will slightly add to overhead), and 1 is most readable not compatible with all compilers.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tom
  • 6,601
  • 12
  • 40
  • 48
  • 41
    You actually think the compilers going to wait until runtime to negate a constant? – GManNickG Feb 12 '10 at 18:16
  • 25
    To follow up so I don't seem like a jerk, no compiler will actually waste it's time doing that. Compilers are heavy optimizers, and if it knows the results will always be the same, it'll put that in there instead. It will never wait until runtime to evaluate `int i = 12 + 3 * 4;`; it'll just say `int i = 24;`. Worrying about performance like that a common problem, don't feel bad. Optimizations comes *last*, and when it does come you have to time your code and look at the assembly output, not guess. Even if it did cost a cycle, I'd go for the most readable solution. Only when it proved to be a – GManNickG Feb 12 '10 at 18:21
  • 12
    problem would I switch to faster solution, timing them to make sure they were indeed faster. When given a choice between readability and a cycle, choose readability. :) It's easy to make good code fast, but hard to make "fast" code good. – GManNickG Feb 12 '10 at 18:23
  • 20
    When using the macros, remember that `(x == TRUE)` is not the same as `(x)`. The former is true only if `x` holds the value of `TRUE`. The latter is true for any non-zero value. – Devon_C_Miller Feb 12 '10 at 18:24
  • +1 @Devon, most of the time I only use the constants as return values. – Seth Feb 12 '10 at 18:30
  • 6
    I advise against defining special boolean macros; this only tempts novice programmers to write things like `if(foo == TRUE)` or `if(foo == FALSE)`, which is an atrocity in most languages, but even more so in C, where any scalar value `!= 0` is considered to be true in boolean contexts; for similar, but less severe reasons, I dislike `if(foo != NULL)` and `if(foo == NULL)` for pointers; as this can't introduce bugs as a comparison to `TRUE` can, it's merely a matter of taste, but using `if(foo)` and `if(!foo)` for any scalar value is imo more in tune with the C language look-and-feel – Christoph Feb 12 '10 at 18:57
  • 1
    http://stackoverflow.com/questions/1921539/using-boolean-values-in-c – jamesdlin Feb 12 '10 at 19:38
  • *"what is the best ..."* is *always subjective, and too easily argumentative to be risked. I edited the question text to help, but even that isn't safe. Finally, I'm with jamesdlin... – dmckee --- ex-moderator kitten Feb 14 '10 at 05:09
  • @GManNickG actually I would expect this to be missed by compilers when the constant is used across compilation unit boundaries *("in a different C file")*. Optimizing it out would require the code to be optimized after linking as the value can't be known during the compilation of the current compilation unit *(before linking)*. Any ideas how compilers avoid this? – Philip Couling Aug 21 '14 at 16:28
  • 1
    Umm... I'm no C expert but isn't `!(FALSE)` *logical* negation? Otherwise if `!` were bitwise, it would evaluate to `-1`, no? – Cyoce Apr 29 '16 at 07:22

15 Answers15

144

Just include <stdbool.h> if your system provides it. That defines a number of macros, including bool, false, and true (defined to _Bool, 0, and 1 respectively). See section 7.16 of C99 for more details.

C. K. Young
  • 219,335
  • 46
  • 382
  • 435
22

Just use 0 or 1 directly in the code.

For C programmers, this is as intuitive as true or false.

b.roth
  • 9,421
  • 8
  • 37
  • 50
  • 63
    For C programmers, -1 is also true, since it is not a zero. For that matter, 42 and -234 are also true values. I've seen -1, -2 and other values as true. Some functions return 0 (zero) as successful. Hmmm, so much for consistency. – Thomas Matthews Feb 12 '10 at 19:04
  • 1
    I usually just see 1 or -1 used as true values. -1 because it's all-ones in binary. I'd love to know where you found -2. – Mike DeSimone Feb 12 '10 at 19:16
  • 8
    I agree with Thomas. The fact that 0 is used as an error code for "no error" (and often also as an `int` type) sometimes makes it non-obvious whether a value is supposed to be used in a boolean context. – jamesdlin Feb 12 '10 at 19:35
  • 13
    Think of a function returning 0 for no-error, as answering the question "did you have any problem?" - "0=false=no". `int fail = close(fd); if (!fail) { great(); } else { weep(); }` – squelart Feb 14 '10 at 05:26
  • 2
    @squelart: The problem is a lot of functions that return boolean values don't have that semantic and return a true value on success, false on failure. (For example, much of the Win32 API is designed this way.) – jamesdlin Feb 16 '10 at 04:06
  • You're right, the different return patterns are confusing. But if the initial developer used the above suggestion when first using a function (at which point the dev would know already, or read about, the return value), maintenance would hopefully be easier later on... – squelart Feb 16 '10 at 06:55
  • 1
    The pattern of returning 0 to indicate success is part of a larger pattern, as follows: a function returns a positive integer value (for example, count of bytes processed, or elapsed time, etc.) if it is successful. Failure is indicated by returning a negative integer. If we now apply this pattern to a function that only returns success or failure, we are left with -1 for failure and 0 for success. Many Linux/Unix system calls and library functions follow this pattern, so it's good to be familiar with it. – John Vincent Jan 05 '16 at 12:16
  • Some values are not so true as `if (0.4)` and `if (abs(0.4))` differ. – chux - Reinstate Monica Aug 17 '18 at 13:47
  • I do this sometimes: Positive : True / Success Codes 0 : Undefined / Uninitialized Negative: False / Failure Codes – KANJICODER Apr 15 '20 at 21:51
21

I usually do a:

typedef enum {FALSE = 0, TRUE} boolean;
Macarse
  • 91,829
  • 44
  • 175
  • 230
  • 6
    why do you explicitly set FALSE=0? Isn't the first element of an enum automatically 0? – lindelof Aug 13 '11 at 20:06
  • 17
    @lindelof It's just in case they add [`FileNotFound`](http://thedailywtf.com/Articles/What_Is_Truth_0x3f_.aspx) to the front of that enum. ;-) – C. K. Young Feb 13 '13 at 22:08
  • 2
    @lindelof It makes sense. Making sure that FALSE is 0, is the only important thing. TRUE can be whatever as long as it is different. – klutt Apr 20 '19 at 10:26
6

Whichever of the three you go with, compare your variables against FALSE, or false.

Historically it is a bad idea to compare anything to true (1) in c or c++. Only false is guaranteed to be zero (0). True is any other value.   Many compiler vendors have these definitions somewhere in their headers.  

#define TRUE 1
#define FALSE 0

This has led too many people down the garden path.   Many library functions besides chartype return nonzero values not equal to 1 on success. There is a great deal of legacy code out there with the same behavior.

Bob Wakefield
  • 814
  • 9
  • 16
  • 3
    I have noticed that comparisons against TRUE fail against uninitialized variables. It's better to initialize your booleans and compare against FALSE. An enum is better if you truly need three values; no, yes, and donotknow. Initialize the enum to donotknow. Don't treat the enum as if it were boolean. It isn't. – Bob Wakefield Sep 01 '13 at 17:39
  • Why not `#define TRUE !FALSE #define FALSE 0`? – The incredible Jan Sep 21 '22 at 13:03
  • That would be fine. It won’t fix the root problem with testing against TRUE. – Bob Wakefield Oct 28 '22 at 19:02
5

With the stdbool.h defined bool type, problems arise when you need to move code from a newer compiler that supports the bool type to an older compiler. This could happen in an embedded programming environment when you move to a new architecture with a C compiler based on an older version of the spec.

In summation, I would stick with the macros when portability matters. Otherwise, do what others recommend and use the bulit in type.

Doug T.
  • 64,223
  • 27
  • 138
  • 202
4

Any int other than zero is true; false is zero. That way code like this continues to work as expected:

int done = 0;   // `int` could be `bool` just as well

while (!done)
{
     // ...
     done = OS_SUCCESS_CODE == some_system_call ();
}

IMO, bool is an overrated type, perhaps a carry over from other languages. int works just fine as a boolean type.

wallyk
  • 56,922
  • 16
  • 83
  • 148
  • 1
    Re "overrated": In C++, `bool` is a separate type so it can participate in function overloading, for much of the same reason why character constants are of type `char` in C++. Of course, this doesn't apply in C, which has no function overloading. – C. K. Young Feb 12 '10 at 18:38
  • 6
    No, C is broken in that it doesn't distinguish between boolean and integer. – starblue Feb 12 '10 at 18:48
  • 2
    C is hardly broken. An integer is a set of booleans which may be manipulated in parallel. Evaluating the set as a whole is their ORed value. – wallyk Feb 12 '10 at 19:05
  • 1
    @starblue: C99 introduced a dedicated boolean type; if it eases your mind, you can pretend that C automatically converts scalar values to `_Bool` in boolean contexts, a feature found in many dynamic languages as well – Christoph Feb 12 '10 at 19:08
  • 2
    The nice thing about `_Bool` is that it allows the compiler to store it in whatever way works best (a byte, a word, a bit, whatever); maybe even giving you the option of determining its size at compile time (like in some compilers, where you can specify an `int` as 2 or 4 bytes, or a `long` as 4 or 8 bytes). Have a processor that wants to access things as words? Make `_Bool` the word size. Does your processor access bytes as easily as words? Make it a byte to save space. Got bit-access instructions? Maybe, maybe not. Continuing C's long tradition of not nailing down `int` sizes... – Mike DeSimone Feb 12 '10 at 19:21
  • 1
    I can live with the way C works, but I think it was a design mistake not to cleanly separate boolean and integer types. C++ tries to rectify that, but is hindered by the need for backward compatibility with C. That the same mistake is made in other languages doesn't make it any better. – starblue Feb 12 '10 at 19:25
  • 1
    @starblue Would not call it a mistake. It made complete sense in the 70:ths. – klutt Apr 20 '19 at 11:02
4

You can test if bool is defined in C99's stdbool.h with

#ifndef __bool_true_false_are_defined || __bool_true_false_are_defined == 0
//typedef or define here
#endif
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Nick Van Brunt
  • 15,244
  • 11
  • 66
  • 92
  • Sorry about my last comment, my PDF search facility is broken. See section 7.16 for more info on `__bool_true_false_are_defined`. – C. K. Young Feb 12 '10 at 18:33
2

I would go for 1. I haven't met incompatibility with it and is more natural. But, I think that it is a part of C++ not C standard. I think that with dirty hacking with defines or your third option - won't gain any performance, but only pain maintaining the code.

anthares
  • 11,070
  • 4
  • 41
  • 61
2

I used to use the #define because they make code easier to read, and there should be no performances degradation compared to using numbers (0,1) coz' the preprocessor converts the #define into numbers before compilation. Once the application is run preprocessor does not come into the way again because the code is already compiled.

BTW it should be:

#define FALSE 0 
#define TRUE 1

and remember that -1, -2, ... 2, 3, etc. all evaluates to true.

Marco Demaio
  • 33,578
  • 33
  • 128
  • 159
  • TRUE is a write-only value -- when reading/comparing, etc., any non-zero value needs to be treated as true. – Jerry Coffin Feb 12 '10 at 18:24
  • 2
    for some reason TRUE seems to commonly be defined as #define TRUE !(FALSE) – Tom Feb 12 '10 at 19:14
  • 3
    @Tom - That's because `!1` returns 0, but `!0` returns a true value, which could be a wide variety of numbers. `#define TRUE !(FALSE)` makes sure that `TRUE == !0` regardless of what exact value `!0` returns. – Chris Lutz Feb 12 '10 at 20:10
2

I prefer (1) when I define a variable, but in expressions I never compare against true and false. Just take the implicit C definition of if(flag) or if(!flag) or if(ptr). That’s the C way to do things.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Lothar
  • 12,537
  • 6
  • 72
  • 121
2

I don't know you specific situation. Back when I was writing C programs, we have always used #2.

#define FALSE = 0
#define TRUE = !FALSE

This might be otherwise under alien platform to DOS or Intel-based processors. But I used to use both C and ASM together writing graphic libraries and graphical IDE. I was a true fan of Micheal Abrash and was intending to learn about texture mapping and so. Anyway! That's not the subject of the question here!

This was the most commonly used form to define boolean values in C, as this headerfile stdbool.h did not exist then.

Will Marcouiller
  • 23,773
  • 22
  • 96
  • 162
1

There is no real speed difference. They are really all the same to the compiler. The difference is with the human beings trying to use and read your code.

For me that makes bool, true, and false the best choice in C++ code. In C code, there are some compilers around that don't support bool (I often have to work with old systems), so I might go with the defines in some circumstances.

T.E.D.
  • 44,016
  • 10
  • 73
  • 134
1

1 is most readable not compatible with all compilers.

No ISO C compiler has a built in type called bool. ISO C99 compilers have a type _Bool, and a header which typedef's bool. So compatability is simply a case of providing your own header if the compiler is not C99 compliant (VC++ for example).

Of course a simpler approach is to compile your C code as C++.

Clifford
  • 88,407
  • 13
  • 85
  • 165
  • 1
    Any C code of sufficient complexity will not compile with a C++ compiler. If you want to use a C++ compiler, then code C++. – klutt Apr 20 '19 at 11:10
  • @Broman I don't think complexity has much to do with it; rather subtle semantic differences. C++'s stronger type checking will issue issue diagnostic that C compilation does not. For the most part it is possible to resolve such issues and for the code to be both valid and semantically identical in both languages, and most often the result will be better code in any case. But it is true that a large (rather than necessarily _complex_) C code base is unlikely to compile un-modified. – Clifford Apr 20 '19 at 11:31
  • True that it's not strictly about complexity. What I meant was that most non-trivial programs will include a malloc call, and then you need to cast. If you're going to compile it with a C++ compiler, why not just code C++ instead? – klutt Apr 20 '19 at 11:34
  • @Broman If you compile it as C++, it is C++, even if it is also valid C. The use of malloc() and the need to cast is one instance where making the C code C++ compilable results in _marginally_ worse C code. – Clifford Apr 20 '19 at 11:39
  • @Broman Moreover, it is a very old answer. VC++ has much more comprehensive C99 support by now, including stdbool.h. The C++ aside really only applied if you were stuck with C90, which is increasingly unlikely. – Clifford Apr 20 '19 at 11:43
0

I prefer the third solution, i.e. using 1 and 0, because it is particularly useful when you have to test if a condition is true or false: you can simply use a variable for the if argument.
If you use other methods, I think that, to be consistent with the rest of the code, I should use a test like this:

if (variable == TRUE)
{
   ...
}

instead of:

if (variable)
{
   ...
}
Maurizio Reginelli
  • 3,152
  • 2
  • 27
  • 41
0

I prefer to use

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

or directly in the code

if (flag == (0==0)) { ... }

The compiler will take care of that. I use a lot of languages and having to remember that FALSE is 0 bothers me a lot; but if I have to, I usually think about that string loop

do { ... } while (*ptr);

and that leads me to see that FALSE is 0

debuti
  • 623
  • 2
  • 10
  • 20