2009-08-21 142 views
73

以这种方式将整数转换为布尔值的原因是什么?为什么要用!!将int转换为bool时?

bool booleanValue = !!integerValue; 

,而不是仅仅

bool booleanValue = integerValue; 

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

+2

我猜问题是,为什么前者不会导致C4800要么因为即使“铸造表达为bool类型不会禁用警告,这是由设计。” (MS) – Tobias 2009-08-21 15:14:06

+0

嗯,这实际上是它的地方...人们混淆C++和C – 2009-10-22 09:01:38

+2

双重否定后,值保证是0或1;原始值可能是任何int值。 – 2009-08-21 06:39:32

回答

108

问题与“!!”成语是它很简洁,很难看,很容易因错字错误,容易丢掉“!”之一,等等。我把它放在“看看我们可以用C/C++多么可爱”的类别中。

只需编写bool isNonZero = (integerValue != 0); ......清楚。

+9

+1“bool isNonZero =(integerValue!= 0);”。当代码使用bool的代码混合整数,双精度,ptrs等时,我总是讨厌它。他们是不同的类型,应该这样对待。将bool隐式转换为数字类型是一种同时性。 – 2009-08-21 07:13:41

+8

我没有看到将int/pointers指定为bools的问题 - 这是一个C/C++库存语言,任何熟悉它们的开发者都应该知道它。然而,有时候你想避免编译器警告等等 - 在这种情况下,一个明确的比较(或者一个强制转换)肯定比相对难懂的'!!'技巧更可取。 – 2009-08-21 07:26:48

+0

Ints和bools是不同的。为什么应该0 = false。这是布尔型之前的日子的宿醉。这也意味着!! a并不一定等于反直觉。 – 2009-08-21 07:43:09

13

因为!integerValue装置integerValue == 0和!! integerValue从而意味着integerValue!= 0,有效的表达式返回一个布尔值。后者是一个信息丢失的演员。

49

从历史上看,使用了!!成语,以确保您的布尔真的包含预期的bool样变量的两个值之一,因为C和C++没有一个真正的bool类型,我们用int小号伪造了。这与现实中的“真实”bool s不太一样。

但使用!!是记录(编译器和未来的任何人在你的代码的工作都),是的,你真的打算到int转换为bool的有效手段。

+9

如果OP甚至不明白它的含义,我不会说“有效的记录手段”。一个更好的方法是static_cast (integerValue)。 – arolson101 2009-08-21 13:41:12

+10

OP可能不知道“List ”的含义,或者是'|| ='。 '!!'在C和C++领域中是一个非常非常根深蒂固的成语。如果有人不知道,他/她应该学习 - 然后对是否使用它做出自己的合理评估。 – 2009-08-21 15:19:13

+5

'bool var =(bool)intVar;'?有什么问题? – bobobobo 2009-12-04 15:48:11

5

一个bool只能有两个状态,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-08-21 07:28:11

+0

我认为你让BOOL和bool混淆。用bool,你会得到一个真正的bool,并且有一个隐式的转换,因此是真的还是假的。 – Recep 2009-08-21 10:36:46

+2

C++中bool的状态不是1和0,但是是true和false。 – 2009-08-21 16:08:49

-1

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

对于编译器来说,它最终不会有所作为。

+0

生成的代码可能会“较慢”:整数将需要测试以查看它是否为零。但是,对于表示为0/1二进制的布尔值,不需要测试。 – 2009-08-21 16:10:45

+2

但是,有了这个理性,我们应该对每个虚拟函数调用都有一个性能警告...... – gimpf 2009-12-04 16:16:09

+0

您可能想要阅读:http://stackoverflow.com/a/1847949/62921 – ForceMagic 2013-08-02 02:22:05

-2

我从来不喜欢转换为bool数据类型的这种技术 - 它的气味错了!

相反,我们使用了一个名为boolean_cast方便的模板中找到here。这是一个灵活的解决方案,它在它在做什么更加明确,可以使用如下:

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

这有点矫枉过正不是吗?我的意思是在一天结束时转换为布尔是精度的损失,并归结为类似 返回b?真假; 这与大约相同!! TRUE个人而言,这是过度工程化的类STL恋物癖。 – 2009-08-21 12:18:07

+0

我认为你不同意使用boolean_cast然后(因此投票) - 那么你会建议我们使用什么呢? – Alan 2009-08-21 13:57:24

+4

我建议你使用这个语言,因为它是用来表示的。高性能,令人讨厌。只需削减学士学位,并完成工作。 – 2009-10-22 09:11:18

4

!!是转换为bool的惯用方式,和它的作品闭嘴的Visual C++编译器的sillywarning关于这种所谓的低效率转换。

我看到其他的答案和评论,很多人不熟悉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] 
> _ 

而且至少有一人认为,如果一个绝对新手,不承认它的意义,那么它的解精。那很愚蠢。有许多新手不认识或理解。写一个人的代码,以便任何新手都能理解它,这不是专业人士所需要的。甚至没有学生。从排除新手无法识别的操作员和操作员组合的路径开始......好吧,我没有给出这种方法的适当描述的话,对不起。

干杯&心连心,

13

它的使用,因为C语言(和一些预标准的C++编译器太)不具备bool类型,只是int。因此,int s用于表示逻辑值:0应该表示false,其他所有内容都是true!运营商从00返回1。双!被用来反转这些,并在那里确保该值取决于其逻辑值只是01

在C++中,由于引入了合适的bool类型,因此不再需要这样做。但是你不能只更新所有的遗留源,而且你不应该因为C和C++的向后兼容(大部分时间)。但是许多人仍然这样做,出于同样的原因:保持他们的代码与旧编译器向后兼容,旧编译器仍然不理解bool s。

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

+0

很明显。 +1 :) – zx81 2014-05-24 00:53:51

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 

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

1

user143506的答案是正确的,但对于一个可能的性能问题我相比,ASM的possibilies:

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); 
} 
相关问题