77

What can be a reason for converting an integer to a boolean in this way?

bool booleanValue = !!integerValue;

instead of just

bool booleanValue = integerValue;

All I know is that in VC++7 the latter will cause C4800 warning and the former will not. Is there any other difference between the two?

sharptooth
  • 167,383
  • 100
  • 513
  • 979

10 Answers10

115

The problems with the "!!" idiom are that it's terse, hard to see, easy to mistake for a typo, easy to drop one of the "!'s", and so forth. I put it in the "look how cute we can be with C/C++" category.

Just write bool isNonZero = (integerValue != 0); ... be clear.

Andy E
  • 338,112
  • 86
  • 474
  • 445
user143506
  • 1,463
  • 1
  • 10
  • 7
  • 11
    +1 for "bool isNonZero = (integerValue != 0);". I always hate it when code conflates ints, doubles, ptrs, etc with bool's. They're different types and should be treat as such. The implicit cast of a bool to numeric type is an anchronism. – jon hanson Aug 21 '09 at 07:13
  • 10
    I don't see a problem with treating ints/pointers as bools - it's a stock C/C++ idiom, and any developer proficient in them should be expected to know it. However, sometimes you want to avoid compiler warnings and such - and in those cases an expicit comparison (or a cast) is definitely much preferable to the relatively obscure `!!` trick. – Pavel Minaev Aug 21 '09 at 07:26
  • Ints and bools are different. Why should 0 == false. It's a hangover from the days before the bool type. It also means that !!a doesn't necessarily equal a which is counter-intuitive. – jon hanson Aug 21 '09 at 07:43
  • 3
    0 is equal to false because the standard says so ;-) !! is a pretty common idiom you just seem to be not familiar with. That doesn_t make it neccessarily bad, except for the use at the beginning of a natural language sentence. – Gunther Piez Aug 21 '09 at 07:58
  • 1
    After over 20 years of C/C++ I'm well familiar with the idiom; i just think it is counter-intuitive! – jon hanson Aug 21 '09 at 08:34
  • 16
    +1 for "look how cute we can be with C/C++". Perfectly sums up so much of the bad coding practices that the C/C++ syntax and loose rules enable. – David Aug 21 '09 at 12:32
  • 8
    -1 for "bool isNonZero = (integerValue != 0);", this is neither more readable nor more "intuitive". If you don't like standard C/C++ idioms like !!, use a different language. – Gunther Piez Dec 04 '09 at 16:07
  • @Pavel: "and in those cases an expicit comparison (or a cast) is definitely much preferable to the relatively obscure !! trick." apparently you have not tried what you're talking about. – Cheers and hth. - Alf Nov 19 '11 at 08:03
  • @Alf I'm not sure what you mean. Are you claiming that there are any cases where `!!i` is preferable to `i != 0`, or what? If yes, then can you give an example? – Pavel Minaev Nov 21 '11 at 23:07
  • @Pavel: i'm just saying that your claim is incorrect. it is not the case that "an explicit comparision (or a cast)" is preferably to !! wrt. "avoid compiler warnings and such", since the single compiler that does have a tendency to warn about the conversion, namely visual c++, is not shut up by a cast, but is shut up by !!. so you're factually wrong. regarding all the value judgments, like "relatively obscure", well you need to get the technical facts right before being in a position to make value judgments. – Cheers and hth. - Alf Nov 22 '11 at 07:11
  • @Alf It is "shut up" by an explicit comparison, though, hence why my comment said "explicit comparison _or_ cast". And my answer was not intended to be VC-specific, but cover as much ground as possible - in a different compiler that would complain about int-to-bool implicit conversion, a cast may well work (indeed, the fact that there's a warning on explicit cast in VC, I personally consider a bug). In any case, this all is very much non-relevant to the value judgement in question, and I still stand by it. – Pavel Minaev Nov 22 '11 at 18:13
  • @PavelMinaev the fact that you're calling it a 'trick' is an indication that you oughtn't be doing it. The thing about tricks is that they are, by definition, hard to understand. Why conflate your code? Perhaps every C/C++ developer should be so knowledgeable, but everyone has to learn somewhere--why trick the newbies? To save a few character strokes? – weberc2 Nov 04 '14 at 04:54
  • @weberc2 I referred specifically to the use of `!!` as a "trick" above, not to treatment of zeros and null pointers and false in C++. The latter is by design, and is widely recognized, understood, and practiced in idiomatic C++, so there's no issue with readability when using it (and it is further supported by standard library, that uses truth checks for e.g. streams). The former is indeed an obscure trick that is seen very rarely. – Pavel Minaev Nov 04 '14 at 17:12
  • @hirschhornsalz `false` may be `zero` because the standard says so, but is `1` the best choice to use to represent `true` in an integer form, I'd be tempted with `-1` on the basis that that has all the bits set (doesn't it) rather than just the LSB - or is there a reason not to do that? – SlySven Sep 22 '16 at 22:47
50

Historically, the !! idiom was used to ensure that your bool really contained one of the two values expected in a bool-like variable, because C and C++ didn't have a true bool type and we faked it with ints. This is less of an issue now with "real" bools.

But using !! is an efficient means of documenting (for both the compiler and any future people working in your code) that yes, you really did intend to cast that int to a bool.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • 10
    I wouldn't say "an efficient means of documenting" if the OP didn't even understand what it meant. A much better way would be static_cast(integerValue). – arolson101 Aug 21 '09 at 13:41
  • 10
    The OP probably didn't know what `List` meant at first, either, or `||=`. `!!` is a very, very deeply ingrained idiom in the C and C++ universe. If anyone doesn't know it, he/she should learn it -- and then make their own reasoned assessment about whether to use it. – T.J. Crowder Aug 21 '09 at 15:19
  • @arolson,@T.J. Crowder: !! may be efficient, but it's ineffective – Lie Ryan Oct 30 '10 at 09:04
  • Can a "real" bool have more than two values? For instance, what is the result of (bool)1 ^ (bool)2 Is it 0 or 3? – dspyz Dec 30 '13 at 20:28
  • 1
    @arolson101: static_cast(integerValue) is a warning in VSCPP 2015 (v14). If warnings are errors for you (or for your code reviewer), you're out of luck w/ that... – lorro Jun 17 '16 at 17:08
  • @bobobobo The fact that its an warning in Visual Studio. Feels awkward to me too... Won't get much more explicit than that. – akaltar Nov 29 '16 at 00:51
  • // bonus: auto foo = !!(10); // foo is bool, not int! – Sergei Vorobiev Oct 11 '17 at 01:01
16

It is used because the C language (and some pre-standard C++ compilers too) didn't have the bool type, just int. So the ints were used to represent logical values: 0 was supposed to mean false, and everything else was true. The ! operator was returning 1 from 0 and 0 from everything else. Double ! was used to invert those, and it was there to make sure that the value is just 0 or 1 depending on its logical value.

In C++, since introducing a proper bool type, there's no need to do that anymore. But you cannot just update all legacy sources, and you shouldn't have to, due to backward compatibility of C with C++ (most of the time). But many people still do it, from the same reason: to remain their code backward-compatible with old compilers which still don't understand bools.

And this is the only real answer. Other answers are misleading.

SasQ
  • 14,009
  • 7
  • 43
  • 43
14

Because !integerValue means integerValue == 0 and !!integerValue thus means integerValue != 0, a valid expression returning a bool. The latter is a cast with information loss.

StampedeXV
  • 2,715
  • 2
  • 24
  • 40
7

Another option is the ternary operator which appears to generate one line less of assembly code (in Visual Studio 2005 anyways):

bool ternary_test = ( int_val == 0 ) ? false : true;

which produces the assembly code:

cmp DWORD PTR _int_val$[ebp], 0
setne   al
mov BYTE PTR _ternary_test$[ebp], al

Versus:

bool not_equal_test = ( int_val != 0 );

which produces:

xor eax, eax
cmp DWORD PTR _int_val$[ebp], 0
setne   al
mov BYTE PTR _not_equal_test$[ebp], al

I know it isn't a huge difference but I was curious about it and just thought that I would share my findings.

Brian
  • 81
  • 1
  • 2
5

A bool can only have two states, 0, and 1. An integer can have any state from -2147483648 to 2147483647 assuming a signed 32-bit integer. The unary ! operator outputs 1 if the input is 0 and outputs 0 if the input is anything except 0. So !0 = 1 and !234 = 0. The second ! simply switches the output so 0 becomes 1 and 1 becomes 0.

So the first statement guarantees that booleanValue will be be set equal to either 0 or 1 and no other value, the second statement does not.

John Scipione
  • 2,360
  • 4
  • 25
  • 28
  • 2
    This is completely wrong. The second statement involves an implicit `int`->`bool` cast. This is well-defined, and any non-zero `int` will be converted to `true`, and 0 will be converted to `false`. The warning that VC++ gives there is actually a "performance warning", and has nothing to do with this. – Pavel Minaev Aug 21 '09 at 07:28
  • I think you are confusing BOOL with bool. With bool, you get a real bool with an implicit cast, hence true or false. – Recep Aug 21 '09 at 10:36
  • 2
    The States of a bool in C++ are not 1 and 0, but true and false. – Johannes Schaub - litb Aug 21 '09 at 16:08
  • Thank you, I did not know that. I thought that 0 == false and 1 == true but apparently that is not so. – John Scipione Oct 15 '09 at 19:09
  • you were right the first time john scipione, this has it's place – Matt Joiner Oct 22 '09 at 09:02
4

!! is an idiomatic way to convert to bool, and it works to shut up the Visual C++ compiler's sillywarning about alleged inefficiency of such conversion.

I see by the other answers and comments that many people are not familiar with this idiom's usefulness in Windows programming. Which means they haven't done any serious Windows programming. And assume blindly that what they have encountered is representative (it is not).

#include <iostream>
using namespace std;

int main( int argc, char* argv[] )
{
    bool const b = static_cast< bool >( argc );
    (void) argv;
    (void) b;
}
> [d:\dev\test]
> cl foo.cpp
foo.cpp
foo.cpp(6) : warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)

[d:\dev\test]
> _

And at least one person thinks that if an utter novice does not recognize its meaning, then it's ungood. Well that's stupid. There's a lot that utter novices don't recognize or understand. Writing one's code so that it will be understood by any utter novice is not something for professionals. Not even for students. Starting on the path of excluding operators and operator combinations that utter novices don't recognize... Well I don't have the words to give that approach an appropriate description, sorry.

halfer
  • 19,824
  • 17
  • 99
  • 186
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • I had a problem already with converting BOOL aka int to bool. The BOOL result was coming from C compiled code. I had to manually convert the BOOL to bool as cpp bool would not recognize the value as being true. eg: BOOL b = -1; bool bb = b; bb == true; // is false!!!! I had to do BOOL b = -1; bool bb = b != 0; – user13947194 Aug 17 '23 at 20:46
  • The following code produces exit code 42 (all OK), and with modern Visual C++ does not even produce a warning: `#include auto main() -> int { BOOL b = -1; bool bb = b; return (bb == true? 42 : 666); } ` – Cheers and hth. - Alf Aug 24 '23 at 17:57
1

The answer of user143506 is correct but for a possible performance issue I compared the possibilies in asm:

return x;, return x != 0;, return !!x; and even return boolean_cast<bool>(x) results in this perfect set of asm instructions:

test    edi/ecx, edi/ecx
setne   al
ret

This was tested for GCC 7.1 and MSVC 19 2017. (Only the boolean_converter in MSVC 19 2017 results in a bigger amount of asm-code but this is caused by templatization and structures and can be neglected by a performance point of view, because the same lines as noted above may just duplicated for different functions with the same runtime.)

This means: There is no performance difference.

PS: This boolean_cast was used:

#define BOOL int
// primary template
template< class TargetT, class SourceT >
struct boolean_converter;

// full specialization
template< >
struct boolean_converter<bool, BOOL>
{
  static bool convert(BOOL b)
  {
    return b ? true : false;
  }
};

// Type your code here, or load an example.
template< class TargetT, class SourceT >
TargetT boolean_cast(SourceT b)
{
  typedef boolean_converter<TargetT, SourceT> converter_t;
  return converter_t::convert(b);
}

bool is_non_zero(int x) {
   return boolean_cast< bool >(x);
}
-1

No big reason except being paranoid or yelling through code that its a bool.

for compiler in the end it wont make difference .

Learner
  • 597
  • 1
  • 5
  • 17
  • The code generated may well be "slower": the integer will require a test to see whether it is zero. However, for a boolean that's represented as 0 / 1 binary, no test is needed. – Johannes Schaub - litb Aug 21 '09 at 16:10
  • 2
    But, well, with this rational we should have a performance warning for every virtual function call... – gimpf Dec 04 '09 at 16:16
-2

I've never like this technique of converting to a bool data type - it smells wrong!

Instead, we're using a handy template called boolean_cast found here. It's a flexible solution that's more explicit in what it's doing and can used as follows:

bool IsWindow = boolean_cast< bool >(::IsWindow(hWnd));
Alan
  • 13,510
  • 9
  • 44
  • 50
  • 9
    It's a bit of an overkill isn't it? I mean at the end of the day conversion to bool is a loss in precision and boils down to something like return b ? true : false; Which is about the same as !!TRUE Personally this is overengineered STL-like fetish. – Igor Zevaka Aug 21 '09 at 12:18
  • I take it you don't agree with using boolean_cast then (hence the down vote) - what would you suggest we use then? – Alan Aug 21 '09 at 13:57
  • 6
    I suggest you use the language as it was meant to be used. High performance, and nasty. Just cut the BS and get the job done. – Matt Joiner Oct 22 '09 at 09:11