What is the performance implication of converting to bool in C++?
Asked Answered
P

11

49

[This question is related to but not the same as this one.]

My compiler warns about implicitly converting or casting certain types to bool whereas explicit conversions do not produce a warning:

long t = 0;
bool b = false;
b = t;                    // performance warning: forcing long to bool
b = (bool)t;              // performance warning
b = bool(t);              // performance warning
b = static_cast<bool>(t); // performance warning
b = t ? true : false;     // ok, no warning
b = t != 0;               // ok
b = !!t;                  // ok

This is with Visual C++ 2008 but I suspect other compilers may have similar warnings.

So my question is: what is the performance implication of casting/converting to bool? Does explicit conversion have better performance in some circumstance (e.g., for certain target architectures or processors)? Does implicit conversion somehow confuse the optimizer?

Microsoft's explanation of their warning is not particularly helpful. They imply that there is a good reason but they don't explain it.

Purslane answered 15/10, 2008 at 21:24 Comment(1)
I worked hard to make this a good and concise question, why the down votes?Purslane
M
37

I was puzzled by this behaviour, until I found this link:

http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=99633

Apparently, coming from the Microsoft Developer who "owns" this warning:

This warning is surprisingly helpful, and found a bug in my code just yesterday. I think Martin is taking "performance warning" out of context.

It's not about the generated code, it's about whether or not the programmer has signalled an intent to change a value from int to bool. There is a penalty for that, and the user has the choice to use "int" instead of "bool" consistently (or more likely vice versa) to avoid the "boolifying" codegen. [...]

It is an old warning, and may have outlived its purpose, but it's behaving as designed here.

So it seems to me the warning is more about style and avoiding some mistakes than anything else.

Hope this will answer your question...

:-p

Metal answered 15/10, 2008 at 21:46 Comment(2)
By the way, thanks to Mike B for his edition: I was searching how to "quote" the text, and failing... :-pMetal
As usual with Microsoft, the link is no longer valid since "Microsoft Connect Has Been Retired"Cornela
E
13

The performance is identical across the board. It involves a couple of instructions on x86, maybe 3 on some other architectures.

On x86 / VC++, they all do

cmp DWORD PTR [whatever], 0
setne al

GCC generates the same thing, but without the warnings (at any warning-level).

Eyebright answered 15/10, 2008 at 21:26 Comment(1)
Two instructions on ARM and MIPS as well :-)Handgrip
G
5

The performance warning does actually make a little bit of sense. I've had it as well and my curiousity led me to investigate with the disassembler. It is trying to tell you that the compiler has to generate some code to coerce the value to either 0 or 1. Because you are insisting on a bool, the old school C idea of 0 or anything else doesn't apply.

You can avoid that tiny performance hit if you really want to. The best way is to avoid the cast altogether and use a bool from the start. If you must have an int, you could just use if( int ) instead of if( bool ). The code generated will simply check whether the int is 0 or not. No extra code to make sure the value is 1 if it's not 0 will be generated.

Gordy answered 15/10, 2008 at 21:44 Comment(2)
sounds plausible, but i wonder why the explicit conversions don't produce the warningPurslane
There are warnings on all casts / conversions. The cases where there is no warning are just code constructs that effect conversions. The compiler can't read your mind and it doesn't know that you are just converting and nothing else.Gordy
I
3

As far as I know, there is no warning on any other compiler for this. The only way I can think that this would cause a performance loss is that the compiler has to compare the entire integer to 0 and then assign the bool appropriately (unlike a conversion such as a char to bool, where the result can be copied over because a bool is one byte and so they are effectively the same), or an integral conversion which involves copying some or all of the source to the destination, possibly after a zero of the destination if it's bigger than the source (in terms of memory).

It's yet another one of Microsoft's useless and unhelpful ideas as to what constitutes good code, and leads us to have to put up with stupid definitions like this:

template <typename T>
inline bool to_bool (const T& t)
  { return t ? true : false; }
Intelligencer answered 15/10, 2008 at 21:28 Comment(5)
Or you could disable the warning.Eyebright
I think MS included the error because it is an implicit conversion to bool and thus isn't type safe. They could have certainly chosen a better error message though. I prefer the b = t != 0 method for suppressing this, as it is clearly an operation that takes a certain type and returns bool.Pyrogallate
It is unbelievable that you have the correct answer and you are still thinking that this warning is useless. You said it yourself: a cast would only compare the lower significant bits ! therefore microsoft code generator actually saves the ass of everybody here. Because e.g. test a pointer in a boolean context without this compiler feature, it would only cast to bool which is a often 1 byte length. thus you would have crashes when your pointer is like that: 0x56b6cc00 just because the last byte is 00 it would yield 'false'... wrongly.Heredity
@Heredity - I've never seen a compiler that generates broken code like that for casting any type to bool. Certainly VC++ doesn't.Aplomb
I have actually witnessed this exact error in an Obj-C application compiled via xcode circa 2010. Inadvertently casting an id (pointer) to BOOL (char) then using the result as a misguided nil (null) check resulting in false-negatives leading to memory leaks and occassionally crashes. Seems like it was fixed a while ago when Apple made BOOL a bool - bignerdranch.com/blog/bools-sharp-corners .Doorplate
S
3

Sounds like premature optimization to me. Are you expecting that the performance of the cast to seriously effect the performance of your app? Maybe if you are writing kernel code or device drivers but in most cases, they all should be ok.

Servant answered 15/10, 2008 at 21:28 Comment(3)
As a matter of fact I am writing a device driver. And I am also curious.Purslane
Even in device drivers it's not really important, but curiosity is a valid reason as well :)Beam
what optimization ? you cannot override the behavior of the code generator, like microsoft said, this is hardcoded in the compiler. thus there is no way to really do a "cast to bool" like you would "cast to char", that would yield a typical and expected MSB part truncation from a larger type. when casting to bool microsoft has supposed that everybody wants to test all the bits of the larger type against 0. they are just warning that the generated code is doing that. which is not natural !Heredity
N
1
long t;
bool b;
int i;
signed char c;
...

You get a warning when you do anything that would be "free" if bool wasn't required to be 0 or 1. b = !!t is effectively assigning the result of the (language built-in, non-overrideable) bool operator!(long)

You shouldn't expect the ! or != operators to cost zero asm instructions even with an optimizing compiler. It is usually true that int i = t is usually optimized away completely. Or even signed char c = t; (on x86/amd64, if t is in the %eax register, after c = t, using c just means using %al. amd64 has byte addressing for every register, BTW. IIRC, in x86 some registers don't have byte addressing.)

Anyway, b = t; i = b; isn't the same as c = t; i = c; it's i = !!t; instead of i = t & 0xff;

Err, I guess everyone already knows all that from the previous replies. My point was, the warning made sense to me, since it caught cases where the compiler had to do things you didn't really tell it to, like !!BOOL on return because you declared the function bool, but are returning an integral value that could be true and != 1. e.g. a lot of windows stuff returns BOOL (int).

This is one of MSVC's few warnings that G++ doesn't have. I'm a lot more used to g++, and it definitely warns about stuff MSVC doesn't, but that I'm glad it told me about. I wrote a portab.h header file with stubs for the MFC/Win32 classes/macros/functions I used. This got the MFC app I'm working on to compile on my GNU/Linux machine at home (and with cygwin). I mainly wanted to be able to compile-test what I was working on at home, but I ended up finding g++'s warnings very useful. It's also a lot stricter about e.g. templates...

On bool in general, I'm not sure it makes for better code when used as a return values and parameter passing. Even for locals, g++ 4.3 doesn't seem to figure out that it doesn't have to coerce the value to 0 or 1 before branching on it. If it's a local variable and you never take its address, the compiler should keep it in whatever size is fastest. If it has to spill it from registers to the stack, it could just as well keep it in 4 bytes, since that may be slightly faster. (It uses a lot of movsx (sign-extension) instructions when loading/storing (non-local) bools, but I don't really remember what it did for automatic (local stack) variables. I do remember seeing it reserve an odd amount of stack space (not a multiple of 4) in functions that had some bools locals.)

Using bool flags was slower than int with the Digital Mars D compiler as of last year: http://www.digitalmars.com/d/archives/digitalmars/D/opEquals_needs_to_return_bool_71813.html (D is a lot like C++, but abandons full C backwards compat to define some nice new semantics, and good support for template metaprogramming. e.g. "static if" or "static assert" instead of template hacks or cpp macros. I'd really like to give D a try sometime. :)

For data structures, it can make sense, e.g. if you want to pack a couple flags before an int and then some doubles in a struct you're going to have quite a lot of.

Neel answered 30/6, 2009 at 15:41 Comment(0)
B
0

Based on your link to MS' explanation, it appears that if the value is merely 1 or 0, there is not performance hit, but if it's any other non-0 value that a comparison must be built at compile time?

Buyse answered 15/10, 2008 at 21:28 Comment(0)
P
0

In C++ a bool ISA int with only two values 0 = false, 1 = true. The compiler only has to check one bit. To be perfectly clear, true != 0, so any int can override bool, it just cost processing cycles to do so.

By using a long as in the code sample, you are forcing a lot more bit checks, which will cause a performance hit.

No this is not premature optimization, it is quite crazy to use code that takes more processing time across the board. This is simply good coding practice.

Pone answered 15/10, 2008 at 21:36 Comment(0)
W
0

Unless you're writing code for a really critical inner loop (simulator core, ray-tracer, etc.) there is no point in worrying about any performance hits in this case. There are other more important things to worry about in your code (and other more significant performance traps lurking, I'm sure).

Winnebago answered 15/10, 2008 at 21:41 Comment(0)
A
0

Microsoft's explanation seems to be that what they're trying to say is:

Hey, if you're using an int, but are only storing true or false information in it, make it a bool!

I'm skeptical about how much would be gained performance-wise, but MS may have found that there was some gain (for their use, anyway). Microsoft's code does tend to run an awful lot, so maybe they've found the micro-optimization to be worthwhile. I believe that a fair bit of what goes into the MS compiler is to support stuff they find useful themselves (only makes sense, right?).

And you get rid of some dirty, little casts to boot.

Arvind answered 15/10, 2008 at 21:44 Comment(0)
F
-1

I don't think performance is the issue here. The reason you get a warning is that information is lost during conversion from int to bool.

Fig answered 15/10, 2008 at 21:29 Comment(3)
all the conversions lose info but only some warnPurslane
jwfern, no, not all conversions. How about conversions to longer types (short to int, int to long, float to double)?Fig
Dima -- I meant all the conversions in this Q, which are from long to boolPurslane

© 2022 - 2024 — McMap. All rights reserved.