Why use !! when converting int to bool?

C++IntegerBoolean

C++ Problem Overview


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?

C++ Solutions


Solution 1 - C++

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.

Solution 2 - C++

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.

Solution 3 - C++

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.

Solution 4 - C++

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.

Solution 5 - C++

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.

Solution 6 - C++

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.

Solution 7 - C++

!! 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.

Solution 8 - C++

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);
}

Solution 9 - C++

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

for compiler in the end it wont make difference .

Solution 10 - C++

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));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionsharptoothView Question on Stackoverflow
Solution 1 - C++user143506View Answer on Stackoverflow
Solution 2 - C++T.J. CrowderView Answer on Stackoverflow
Solution 3 - C++SasQView Answer on Stackoverflow
Solution 4 - C++StampedeXVView Answer on Stackoverflow
Solution 5 - C++BrianView Answer on Stackoverflow
Solution 6 - C++John ScipioneView Answer on Stackoverflow
Solution 7 - C++Cheers and hth. - AlfView Answer on Stackoverflow
Solution 8 - C++kallitokacoView Answer on Stackoverflow
Solution 9 - C++LearnerView Answer on Stackoverflow
Solution 10 - C++AlanView Answer on Stackoverflow