为什么使用!将int转换为bool时?


76

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

bool booleanValue = !!integerValue;

而不只是

bool booleanValue = integerValue;

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


2
两次否定后,该值保证为0或1;否则为0。原始值可以是任何int值。
Martin v。Löwis09年

1
但是,为什么第二个语句不完全相同呢?
09年

2
我猜是问题所在,为什么前者也不会导致C4800,因为即使“将表达式强制类型化为bool也不会禁用警告,这是设计使然。” (MS)
Tobias

2
为什么没有更多的人知道是正确的答案呢?在低级代码中,双重否定很常见
Matt Joiner 2009年

嗯,这实际上已经到位了……人们对C ++和C感到困惑
Matt Joiner

Answers:


112

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

只是写bool isNonZero = (integerValue != 0);...要清楚。


11
+1为“ bool isNonZero =(integerValue!= 0);”。当代码用布尔值将int,double,ptrs等填充到一起时,我总是讨厌它。它们是不同的类型,应该这样对待。将布尔值隐式转换为数字类型是一种过时主义。
jon-hanson 09年

8
我认为将int / pointers当作布尔不是问题-它是C / C ++的一种惯用语言,任何精通它们的开发人员都应该知道这一点。但是,有时您想避免使用编译器警告,在这种情况下,相对比较晦涩的!!技巧,显式比较(或强制转换)绝对是更可取的选择。
2009年

3
0等于false,因为标准是这样说的;-) !! 这是您似乎不熟悉的非常常见的习惯用法。除了在自然语言句子的开头使用以外,这并不一定会使它变糟。
甘瑟·皮兹

16
+1表示“看起来,使用C / C ++会多么可爱”。完美地总结了C / C ++语法和宽松规则所导致的许多不良编码实践。
戴维(David)2009年

8
对于“ bool isNonZero =(integerValue!= 0);”,为-1,这既不易读也不更“直观”。如果您不喜欢!!等标准C / C ++习惯用法,请使用其他语言。
Gunther Piez

49

从历史上看,该!!惯用法用于确保布尔bool变量确实包含-like变量中预期的两个值之一,因为C和C ++没有真正的bool类型,我们使用ints进行了伪造。现在,对于“ real”而言,这不再是一个问题bool

但是,使用!!是一种非常有效的文档编制方法(对于编译器和任何将来在代码中工作的人员而言),是的,您确实打算将其int转换为bool


10
如果OP甚至不了解它的含义,我就不会说“一种有效的记录方法”。更好的方法是static_cast <bool>(integerValue)。
09年

10
OP可能一开始都不知道是什么List<String>意思||=!!是C和C ++领域中非常非常根深蒂固的习语。如果谁不知道,他/她应该学习它-然后对是否使用它进行自己的合理评估。
TJ Crowder

@ arolson,@ TJ Crowder:!! 可能有效,但是无效
Lie Ryan 2010年

“真正的”布尔值可以有两个以上的值吗?例如,(bool)1 ^(bool)2的结果是0还是3?
dspyz 2013年

1
@ arolson101:static_cast <bool>(integerValue)是VSCPP 2015(v14)中的警告。如果警告对您(或您的代码检查者)而言是错误,则表示您不走运……
lorro

14

之所以使用它,是因为C语言(以及一些预标准的C ++编译器)没有bool类型,只是int。因此,ints用来表示逻辑值:0应该是指false,其他所有东西都是true。该!运营商正在恢复100从其他一切。使用Double!来反转它们,并在那里确保该值正好01取决于其逻辑值。

在C ++中,由于引入了适当的bool类型,因此不再需要这样做。但是由于C与C ++的向后兼容性(大多数时候),您不能只更新所有旧版源,也不必这样做。但是出于同样的原因,许多人仍然这样做:使他们的代码与仍然不了解bools的旧编译器向后兼容。

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


13

因为!integerValue表示integerValue == 0,而!! integerValue表示integerValue!= 0,所以返回布尔的有效表达式。后者是信息丢失的演员。


7

另一个选择是三元运算符,它看起来生成的汇编代码少一行(无论如何在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

一个布尔型只能具有两个状态0和1。一个整数可以具有从-2147483648到2147483647的任何状态(假设有符号的32位整数)。一元!如果输入为0,则运算符输出1;如果输入为0,则运算符输出0。因此!0 = 1和!234 = 0。只需切换输出,以便0变为1且1变为0。

因此,第一条语句保证将booleanValue设置为等于0或1,并且没有其他值,第二条语句则没有。


2
这是完全错误的。第二条语句涉及隐式int->bool强制转换。这是定义明确的,任何非零int都将转换为true,而0将转换为false。VC ++给出的警告实际上是“性能警告”,与之无关。
2009年

我认为您将BOOL与bool混淆了。使用布尔,您将获得带有隐式强制转换的真实布尔,因此是true或false。
Recep

2
C ++中布尔的状态不是1和0,而是对与错。
Johannes Schaub-litb

谢谢,我不知道。我以为0 == false和1 == true,但显然并非如此。
约翰·西弗奥妮

您是第一次约翰·斯西皮奥恩(John scipione),这是对的地方
Matt Joiner 2009年

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):警告C4800:'int':强制将值设置为'true'或'false'(性能警告)

[d:\ dev \ test]
> _

至少有人认为,如果一个新手根本不认识它的意思,那就不好了。好吧,这很愚蠢。很多新手根本不认识或理解。编写代码以使任何新手都能理解它对于专业人士而言不是一件容易的事。甚至没有学生。从排除说出新手不认识的运算符和运算符组合的路径开始……好吧,我没有合适的描述来表达这种方法,对不起。


1

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

return x;return x != 0;return !!x;甚至return boolean_cast<bool>(x)在这一套完美的汇编指令的结果:

test    edi/ecx, edi/ecx
setne   al
ret

已针对GCC 7.1和M​​SVC 19 2017进行了测试。(仅MSVC 19 2017中的boolean_converter导致大量的asm代码,但这是由模板化和结构引起的,并且在性能方面可以忽略,因为相同如上所述的行可能会在相同的运行时间中针对不同的功能进行重复。)

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

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

-1

除了被偏执狂或通过代码大吼大叫外,没有什么大的理由。

对于编译器最终不会有所作为。


生成的代码可能会“更慢”:整数将需要进行测试以查看其是否为零。但是,对于以0/1二进制表示的布尔值,不需要测试。
Johannes Schaub-litb

2
但是,基于这种理性,我们应该对每个虚函数调用都发出性能警告...
gimpf

-2

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

取而代之的是,我们使用了一个名为boolean_castfound here的便捷模板。这是一个灵活的解决方案,它在做什么方面更加明确,可以按以下方式使用:

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

8
有点过分了吧?我的意思是说,最终转换为bool会导致精度下降,并归结为return b吗?真假; 与!! TRUE大致相同。就个人而言,这是过度设计的STL迷信。
伊戈尔·泽瓦卡

我认为您当时不同意使用boolean_cast(因此投了反对票)-那么您建议我们使用什么?
艾伦(Alan)2009年

5
我建议您使用原本应该使用的语言。高性能,令人讨厌。只需削减BS并完成工作即可。
马特·乔纳
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.