为何使用!!将int转换为bool时?

时间:2009-08-21 06:36:12

标签: c++ integer boolean

以这种方式将整数转换为布尔值的原因是什么?

bool booleanValue = !!integerValue;

而不仅仅是

bool booleanValue = integerValue;

我所知道的是,在VC ++ 7中,后者将导致C4800 warning ,而前者则不会。两者之间还有其他区别吗?

10 个答案:

答案 0 :(得分:111)

“!!”的问题成语是它简洁,难以看清,容易误认为是错字,容易丢掉其中一个“!”,等等。我把它放在“看起来我们可以用C / C ++变得多么可爱”的类别中。

只需写下bool isNonZero = (integerValue != 0); ......明确。

答案 1 :(得分:49)

从历史上看,!!惯用法用于确保你的bool确实包含bool - 类变量中预期的两个值中的一个,因为C和C ++没有真正的{{ 1}}类型,我们用bool s伪造它。对于“真正的”int来说,这不是一个问题。

但是使用bool是一种有效的文档记录方式(对于编译器和代码中的任何未来人员)是的,你确实打算将!!强制转换为{{1} }}

答案 2 :(得分:14)

之所以使用它是因为C语言(以及一些预先标准的C ++编译器)没有bool类型,只有int。因此,int用于表示逻辑值:0应该表示false,其他所有内容都是true!运算符从10返回0。双!用于反转那些,并且确保该值仅为01,具体取决于其逻辑值。

在C ++中,由于引入了正确的bool类型,因此不再需要这样做了。但是,由于C与C ++的向后兼容性(大多数情况下),您不能只更新所有遗留源,而且您不应该这样做。但是很多人仍然这样做,原因相同:保持他们的代码向后兼容旧的编译器仍然不理解bool

这是唯一真正的答案。其他答案具有误导性。

答案 3 :(得分:13)

因为!integerValue表示integerValue == 0和!! integerValue因此表示integerValue!= 0,一个返回bool的有效表达式。后者是信息丢失的演员。

答案 4 :(得分:6)

另一个选项是三元运算符,它似乎生成一行较少的汇编代码(无论如何都在Visual Studio 2005中):

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

生成汇编代码:

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

对战:

bool not_equal_test = ( int_val != 0 );

产生:

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

我知道这并不是一个巨大的差异,但我很好奇,并且只是认为我会分享我的发现。

答案 5 :(得分:5)

bool只能有两个状态,0和1.假设有符号的32位整数,整数可以具有从-2147483648到2147483647的任何状态。一元!如果输入为0,则运算符输出1,如果输入为0以外的任何值,则输出0。所以!0 = 1和!234 = 0.第二个!只需切换输出,使0变为1,1变为0.

因此第一个语句保证booleanValue将被设置为等于0或1而没有其他值,第二个语句不会。

答案 6 :(得分:4)

!!是转换为bool的惯用方法,它可以阻止Visual C ++编译器愚蠢地警告这种转换的低效率。

我从其他答案和评论中看到很多人不熟悉这个成语在Windows编程中的用处。这意味着他们没有做过任何严肃的Windows编程。盲目地假设他们遇到的是代表性的(事实并非如此)。

#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]
> _

并且至少有一个人认为,如果一个新手不能识别它的含义,那么它就是不合适的。那太愚蠢了。有很多新手不会认识或理解。编写一个代码以便任何完全新手都能理解它并不适合专业人士。甚至不适合学生。从排除操作员和操作员组合的路径开始,说新手不认识......好吧,我没有给出这种方法的说法,对不起。

干杯&amp;第h。,

答案 7 :(得分:1)

user143506的答案是正确的但是对于可能的性能问题,我比较了asm中的可能性:

return x;return x != 0;return !!x;甚至return boolean_cast<bool>(x)会产生完整的asm说明:

test    edi/ecx, edi/ecx
setne   al
ret

这是针对GCC 7.1和2017年MSVC 19测试的。(2017年MSVC 19中的boolean_converter只会产生更大量的asm-code,但这是由模板化和结构引起的,从性能的角度来看可以忽略不计,因为上面提到的相同行可能只是为具有相同运行时的不同函数重复。)

这意味着:没有性能差异。

PS:使用了boolean_cast:

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

答案 8 :(得分:-1)

没有什么大的理由,除了偏执或通过代码大喊大叫它是一个布尔。

对于编译器到底它不会有所作为。

答案 9 :(得分:-2)

我从不喜欢这种转换为bool数据类型的技术 - 它闻起来有点错误!

相反,我们使用的是名为boolean_cast here {{}}}的便捷模板。这是一个灵活的解决方案,在其正在做的事情中更明确,可以按如下方式使用:

bool IsWindow = boolean_cast< bool >(::IsWindow(hWnd));