10

The <windows.h> header comes with its own BOOL type. Peeking at the implementation, it seems FALSE is just a macro for 0, and TRUE is just a macro for 1, but I'm not sure this is specified.

What is the idiomatic way to convert a BOOL to a bool? I can imagine lots of possible ways:

bool a = static_cast<bool>(x);

bool b = x ? true : false;

bool c = (x == TRUE);

bool d = (x != FALSE);

bool e = !!x;

// ...
fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • what do you mean by "idiomatic" ? – Michał Walenciak Aug 29 '13 at 19:58
  • 1
    `bool c = (x == FALSE)`? :) – nullptr Aug 29 '13 at 19:58
  • This is probably inappropriate for SO because it boils down to personal taste, I believe. – László Papp Aug 29 '13 at 19:59
  • bool e = !!x; is the same that bool e = x; ;) – hidrargyro Aug 29 '13 at 20:00
  • @MichałWalenciak It means "How do I do it in a way that any Win32 programmer would immediately recognize and not make him go 'Huh?'". – fredoverflow Aug 29 '13 at 20:00
  • 1
    @hidrargyro No, `bool e = x;` gives me a compiler warning. – fredoverflow Aug 29 '13 at 20:01
  • 1
    @hidrargyro Um. no it isn't. `bool e = !!7;` is perfectly valid C++ (albeit a bit odd). `bool e = 7` is not. You'll get a warning about conversion. – WhozCraig Aug 29 '13 at 20:01
  • 1
    I'd probably use `static_cast` to avoid the warning, but that's more personal preference. I'm sure a good number of people would prefer to double bang it. Anyway, when all sorts of documentation uses `if (!someFunctionReturningBOOL)` and half the Win32 code in existence relies on at least `FALSE` being 0, I think it's safe to assume it is and won't change. – chris Aug 29 '13 at 20:03
  • @WhozCraig `!!7`? Is that the evil twin of `007`? :) – fredoverflow Aug 29 '13 at 20:03
  • @WhozCraig: `bool e = 7;` is also perfectly valid C++. Why should a compiler warn about it? (g++ doesn't, even with `-std=c++11 -pedantic -Wall -Wextra`) – Keith Thompson Aug 29 '13 at 20:06
  • @FredOverflow Absolutely. Making matters worse in a truly MS-fashion, there are places (such as `GetMessage()` where they actually tell you to eval the BOOL result as an `int` to drill into potentially multiple meanings of how that function can return. *Love* those guys. – WhozCraig Aug 29 '13 at 20:07
  • @KeithThompson how positively interesting. My clang (albeit a bit of a hack-job) barks about "potential loss of data" blah blah. Maybe I should update my sources and give it another try. – WhozCraig Aug 29 '13 at 20:09
  • @WhozCraig: Compilers *can* warn about anything they like, including "you used an ugly font to write this code". And warning about possible loss of information on an implicit conversion makes a certain amount of sense -- but in this particular case I'd say it's overkill. – Keith Thompson Aug 29 '13 at 20:11
  • @KeithThompson I agree. It does seem somewhat ballistic. – WhozCraig Aug 29 '13 at 20:12

5 Answers5

9

There's no need for any explicit conversion:

BOOL x = some_value;
bool b = x;

The implicit conversion of a numeric type to bool yields false for a value of 0, and true for any non-zero value.

Incidentally, you've told us how <windows.h> defines FALSE and TRUE. How does it define BOOL? (From your comment, it's typedef int BOOL;)

But some compilers may warn about this implicit conversion, even though it's perfectly valid code. Compilers are free to warn about anything they like, including the ugly font you used to write your code. g++, for example, doesn't complain about the conversion, even with:

g++ -std=c++11 -pedantic -Wall -Wextra ...

But according to this online Visual C++ compiler, VC++ does produce a warning:

warning C4800: 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)

Even with a static_cast, it still produces the warning.

You can avoid the warning by using !!x or x ? true : false. But I'm not sure the cure is any better than the disease.

The simple and correct way to do this is simply to assign the value and rely on the implicit conversion to do the right thing (it will).

If you have an additional requirement to avoid compiler warnings, then this becomes more a question about Visual C++ rather than the C++ language. There may also be some way to inhibit certain warnings without changing the source -- though that risks losing those same warnings when they actually make sense. In a comment, Dieter Lücking suggests:

#pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning)

but that looks like it still requires modifying the source. Perhaps there's something equivalent that doesn't.

One more thing: since BOOL is really type int, this proposed solution:

bool c = (x == TRUE);

is not equivalent to the others. Any non-zero int is treated as true, but only the value 1 is equal to TRUE. The above will set c to false if x == 2, for example -- whereas if (x) would still treat it as a true condition. Never compare boolean values for equality to true or TRUE. (Comparing them to false or FALSE is safer, but still unnecessary; that's what the ! operator is for.)

This all assumes that if you have a value of type BOOL, you only care whether it's falsish or truthy (zero or non-zero). Unfortunately, this may not always be the case. As Ben Voight's answer points out, Microsoft's API includes at least one function, GetMessage, that returns a BOOL result that is not a simple Boolean value. In such a horrible case, conversion from BOOL to bool is not appropriate if you need to distinguish among the multiple non-zero values.

Ultimately, I blame Microsoft for defining a type BOOL for a language that already has a perfectly well behaved built-in bool type. Actually that's not quite fair; it's used in APIs that need to be accessible from both C and C++. Microsoft's definition of BOOL probably goes back to their C implementation, where it makes some sense -- at least prior to C99, which Microsoft still doesn't support. (I don't know whether Microsoft's C compiler support _Bool. Even if it does, _Bool has some semantic differences from int, and changing the definition of BOOL might break some code -- particularly code that uses GetMessage.)

Community
  • 1
  • 1
Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • 2
    This gives me a compiler warning. Otherwise I wouldn't have asked :) – fredoverflow Aug 29 '13 at 20:01
  • 1
    @FredOverflow: What's the warning? (And why didn't you mention that, and quote the warning, in your original question?) Compilers can warn about anything they like; gcc, for example, *doesn't* warn about an implicit conversion from`int` to `bool`. And please update your question to show that typedef. – Keith Thompson Aug 29 '13 at 20:03
  • Sorry, I cannot reproduce the warning at home, because I don't have Visual Studio installed here. I'll get back to you tomorrow! – fredoverflow Aug 29 '13 at 20:04
  • @FredOverflow, There's an online MSVC11 and CTP compiler if it helps: http://rise4fun.com/vcpp – chris Aug 29 '13 at 20:07
  • @KeithThompson I guess: #pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' (performance warning) –  Aug 29 '13 at 20:18
  • 1
    Re: "goes back to their C implementation"... the interface is still C89-compatible, which is a necessary result of backward compatibility requirements. The implementation doesn't matter, return types are part of the interface. – Ben Voigt Aug 29 '13 at 20:28
  • @BenVoigt: I'm still going to blame Microsoft, whether it's really their fault or not. 8-)} – Keith Thompson Aug 29 '13 at 20:31
  • The static cast producing a warning is just...bad. – chris Aug 29 '13 at 20:39
0

It's hard to say how would the win32 programmer do it, but IMHO it should be done by:

bool c = (X == TRUE);

or

bool d = (x != FALSE);

I think it's a bad practice to relay on macro (or any other predefined stuff)
constancy.

One day TRUE may become 0 and FALSE 1 ;)

Michał Walenciak
  • 4,257
  • 4
  • 33
  • 61
  • 2
    That day is now, sort of: [`VARIANT_BOOL`](http://msdn.microsoft.com/en-us/library/cc237864.aspx) can be assigned `VARIANT_FALSE` and `VARIANT_TRUE` with the latter being defined as `(short)-1`, in other words 0xFFFF. On Windows I would suggest always using `bool d = (x != FALSE);`. You cannot expect everyone on your team to know how to convert from `VARIANT_BOOL` to `BOOL` properly. – IInspectable Aug 29 '13 at 22:16
0

There's no safe way to do it, because Win32 BOOL has more than two values.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • That's assuming you need to retain those values. If it's being used sanely, you should only care whether it's truthy or falsish. – Keith Thompson Aug 29 '13 at 20:23
  • 1
    @Keith: That's true for many of the APIs, but the one I linked to returns values from three equivalence classes. – Ben Voigt Aug 29 '13 at 20:26
  • That's a stupid, stupid, stupid API. (Changing the return type from `BOOL` to `int` would solve that problem and make no difference to the API.) – Keith Thompson Aug 29 '13 at 20:30
  • It really is, but as Raymond Chen explained once upon a time, there can only be an error if you do something stupid while passing in the arguments. It won't return a value less than 0 unless it's your fault. Still, there might be others that use something similar to a tribool. – chris Aug 29 '13 at 20:42
  • @chris: I guess [this is the explanation](http://blogs.msdn.com/b/oldnewthing/archive/2013/03/22/10404367.aspx) you're referring to? – Ben Voigt Aug 29 '13 at 20:45
  • @BenVoigt, That's the one, thanks. I actually stopped putting in the `> 0` after that. – chris Aug 29 '13 at 20:58
0

I use a macro:

#define _bool(b) (!!(b)) 

IMO, makes my code more readable.

EDITED: a commenter has challenged my use of underscore in the macro name. To address this, here's a new version which is still generic and still uses the same name _bool, but is compliant, according to this.

namespace MyBool 
{
    template<typename T> inline bool _bool(const T b) 
    {
        return !!b;
    }
}

using namespace MyBool;
Community
  • 1
  • 1
avo
  • 10,101
  • 13
  • 53
  • 81
  • 2
    Names that begin with an underscore in the global namespace are [reserved](http://stackoverflow.com/questions/228783/what-are-the-rules-about-using-an-underscore-in-a-c-identifier). – IInspectable Aug 30 '13 at 09:18
  • Not a problem for me. This macro is used only by my own code and get expanded by pre-processor, so compiler and namespaces know nothing about it. Anyway, one can use `__bool`. – avo Aug 30 '13 at 09:30
  • 1
    A name that contains a double underscore is reserved **everywhere**. This has nothing to do with **your** code either. The rules are there to prevent name clashes with the C++ implementation. You certainly don't want a standard library header include guard to conflict with code using it. A safe alternative would be: `bool bool_(const BOOL b){return !!b;}` – IInspectable Aug 30 '13 at 09:40
  • I live and learn, but I still like the old name `_bool` :) Do you think I'm safe with the new version - edited? – avo Aug 30 '13 at 10:04
0

This is somewhat of an opinion question, but I think there are objective arguments to be made for the various options.

The best choice is:

bool d = (x != FALSE);

This makes the intent very clear to the reader, does not rely on implicit conversions, and makes it clear that there's more going on than a simple assignment.

The second best choice is:

bool b = x ? true : false;

But, to the casual reader, that can seem like a tautology.

I try to avoid implicit conversions in assignments because getting the wrong conversion is a surprising source of bugs. Even when I know the implicit conversion will do the right thing, I tend to do it explicitly, which may be helpful to someone reading the code in the future. Being explicit also allows you to keep the conversion warnings enabled so you catch the other implicit conversions you didn't know you were (ab)using.

The alternatives all have more serious drawbacks.

bool a = static_cast<bool>(x);

This is like hammering a square peg into a round hole. It's more elegant to write an expression that naturally returns the correct type.

bool c = (x == TRUE);

It's generally a bad idea to compare to TRUE, since other non-zero values would convert to false, which is almost certainly an error.

bool e = !!x;

Too clever compared to the alternatives that express exactly what you mean. (I am guilty of having done this in the past.)

bool f = x;

The performance warning MSVC++ emits on the purely implicit conversion seems fair. The compiler has to generate extra code to convert an int to a bool. The bare assignment gives little clue about this extra work. If it's in a tight loop, you might care. (Granted, the performance warning on the static_cast option seems egregious, but we've already ruled that out as less elegant.)

The d and b expressions clearly express the intent and make it obvious that there's more going on here than a direct assignment.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175