为啥用!!将 int 转换为 bool 时?

Posted

技术标签:

【中文标题】为啥用!!将 int 转换为 bool 时?【英文标题】:Why use !! when converting int to bool?为什么用!!将 int 转换为 bool 时? 【发布时间】:2010-11-21 13:46:02 【问题描述】:

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

bool booleanValue = !!integerValue;

而不仅仅是

bool booleanValue = integerValue;

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

【问题讨论】:

双重否定后,保证值为0或1;原始值可能是任何 int 值。 但是为什么第二个语句不完全一样呢? 我想问题是为什么前者也不会导致 C4800,因为即使“将表达式转换为 bool 类型也不会禁用警告,这是设计使然。” (女士) 为什么没有更多的人知道 this 是正确的答案。双重否定在低级代码中很常见 嗯,这确实有它的位置......人们混淆了C++和C 【参考方案1】:

!! 是一种转换为 bool 的惯用方式,它可以关闭 Visual C++ 编译器关于此类转换效率低下的愚蠢警告。

我从其他答案和 cmets 中看到,许多人不熟悉这个习语在 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' : 强制值为 bool 'true' 或 'false' (性能警告) [d:\开发\测试] > _

而且至少有一个人认为,如果一个完全的新手不认识它的意思,那就不好了。好吧,这很愚蠢。有很多完全新手不认识或不理解的东西。编写一个代码以便任何完全的新手都能理解,这不是专业人士的事情。甚至对学生也不行。从排除完全新手无法识别的运算符和运算符组合的路径开始......好吧,我没有话可以对这种方法进行适当的描述,抱歉。

【讨论】:

【参考方案2】:

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

return x;return x != 0;return !!x; 甚至是return boolean_cast&lt;bool&gt;(x) 都产生了这套完美的 asm 指令:

test    edi/ecx, edi/ecx
setne   al
ret

这是针对 GCC 7.1 和 MSVC 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);

【讨论】:

【参考方案3】:

从历史上看,!! 习惯用法用于确保您的 bool 确实包含 bool 类变量中预期的两个值之一,因为 C 和 C++ 没有真正的 bool 类型,我们用ints 伪造它。现在,对于“真实”bools,这已经不是问题了。

但是使用 !! 是一种有效的记录方式(对于编译器和任何未来使用您的代码的人)是的,您确实打算将 int 转换为 bool

【讨论】:

如果 OP 甚至不理解它的含义,我不会说“一种有效的记录方法”。更好的方法是 static_cast(integerValue)。 OP 一开始可能不知道List&lt;String&gt;||= 是什么意思。 !! 是 C 和 C++ 世界中一个非常非常根深蒂固的习语。如果有人不知道,他/她应该学习它——然后对是否使用它做出自己的合理评估。 @arolson,@T.J.克劳德:!!可能有效,但无效 一个“真正的”布尔值可以有两个以上的值吗?比如(bool)1 ^ (bool)2的结果是0还是3? @arolson101: static_cast(integerValue) 是 VSCPP 2015 (v14) 中的警告。如果警告对您(或您的代码审查员)来说是错误的,那么您就不走运了...【参考方案4】:

另一种选择是三元运算符,它似乎可以少生成一行汇编代码(无论如何在 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】:

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

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

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

【讨论】:

【参考方案6】:

“!!”的问题成语是它很简洁,很难看,容易误认为是拼写错误,容易删除“!”中的一个,等等。我把它放在“看看我们可以用 C/C++ 变得多么可爱”类别。 写bool isNonZero = (integerValue != 0); ...清楚一点。

【讨论】:

+1 表示“bool isNonZero = (integerValue != 0);”。当代码将 int、double、ptrs 等与 bool 混为一谈时,我总是讨厌它。它们是不同的类型,应该这样对待。将 bool 隐式转换为数字类型是不合时宜的。 我认为将 ints/pointers 视为 bool 没有任何问题 - 这是一种常见的 C/C++ 习惯用法,任何精通它们的开发人员都应该知道这一点。但是,有时您希望避免编译器警告等 - 在这些情况下,明确比较(或强制转换)绝对比相对晦涩的 !! 技巧更可取。 0 等于 false,因为标准是这样说的 ;-) !!是一个很常见的习语,你似乎并不熟悉。除了在自然语言句子的开头使用之外,这不会使它变得很糟糕。 +1 表示“看看我们使用 C/C++ 可以变得多么可爱”。完美总结了 C/C++ 语法和松散规则导致的许多不良编码实践。 -1 for "bool isNonZero = (integerValue != 0);",这既不可读也不更“直观”。如果您不喜欢像 !! 这样的标准 C/C++ 习语,请使用其他语言。【参考方案7】:

我从不喜欢这种转换为bool 数据类型的技术——它闻起来不对劲!

相反,我们使用了一个名为boolean_cast 的便捷模板,该模板位于here。这是一个灵活的解决方案,它的作用更加明确,可以按如下方式使用:

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

【讨论】:

这有点矫枉过正,不是吗?我的意思是在一天结束时转换为 bool 是精度损失,归结为 return b 之类的东西?真假;这和 !!TRUE 差不多就个人而言,这是过度设计的 STL 式恋物癖。 我认为你不同意使用 boolean_cast (因此投反对票) - 你建议我们使用什么? 我建议您使用本应使用的语言。高性能,而且讨厌。只需削减 BS 并完成工作。【参考方案8】:

除了偏执或通过代码大喊大叫之外没有什么大的原因。

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

【讨论】:

生成的代码可能会“更慢”:整数需要测试以查看它是否为零。但是,对于表示为 0 / 1 二进制的布尔值,不需要测试。 但是,好吧,有了这个理性,我们应该对每个虚函数调用都有一个性能警告......【参考方案9】:

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

所以第一个语句保证 booleanValue 将被设置为 0 或 1 并且没有其他值,第二个语句没有。

【讨论】:

这是完全错误的。第二个语句涉及隐式int->bool 演员表。这是明确定义的,任何非零的int 都将转换为true,0 将转换为false。 VC++给出的警告实际上是一个“性能警告”,与此无关。 我认为您将 BOOL 与 bool 混淆了。使用 bool,你会得到一个带有隐式转换的真正 bool,因此是真或假。 C++中bool的状态不是1和0,而是真假。 谢谢,我不知道。我认为 0 == false 和 1 == true 但显然不是这样。 john scipione 第一次你是对的,这就是它的位置【参考方案10】:

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

【讨论】:

以上是关于为啥用!!将 int 转换为 bool 时?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在使用传统绑定时 bool 可以在没有转换器的情况下为可见性工作

unity c#怎么讲string转换为bool

OCaml:将 bool 转换为 int

不能将 int 转换为 bool

vs里面bool类型如何转换为string类型

为啥 PDO 将我的 bool(false) 参数转换为 string('')?