C++ 为什么要用!!将 int 转换为 bool 时?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1310344/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:31:20  来源:igfitidea点击:

Why use !! when converting int to bool?

c++integerboolean

提问by sharptooth

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?

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

回答by user143506

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.

“!!”的问题 习语是它很简洁,很难看,很容易被误认为是打字错误,很容易去掉一个“!”,等等。我把它归入“看看我们可以用 C/C++ 多可爱”的类别。

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

回答by T.J. Crowder

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 booltype and we faked it with ints. This is less of an issue now with "real" bools.

从历史上看,这个!!习惯用法用于确保您的 bool 确实包含了一个bool-like 变量中预期的两个值之一,因为 C 和 C++ 没有真正的bool类型,我们用ints伪造了它。现在对于 "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 intto a bool.

但是 using!!是一种有效的记录方式(对于编译器和将来在您的代码中工作的任何人),是的,您确实打算将其int转换为bool.

回答by SasQ

It is used because the C language (and some pre-standard C++ compilers too) didn't have the booltype, just int. So the ints were used to represent logical values: 0was supposed to mean false, and everything else was true. The !operator was returning 1from 0and 0from everything else. Double !was used to invert those, and it was there to make sure that the value is just 0or 1depending on its logical value.

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

In C++, since introducing a proper booltype, 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.

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

And this is the only real answer. Other answers are misleading.

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

回答by StampedeXV

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.

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

回答by Brian

Another option is the ternary operator which appears to generate one line less of assembly code (in Visual Studio 2005 anyways):

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

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.

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

回答by John Scipione

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.

bool 只能有 0 和 1 两种状态。假设有符号的 32 位整数,整数可以具有从 -2147483648 到 2147483647 的任何状态。一元!如果输入为 0,则运算符输出 1,如果输入为 0 以外的任何内容,则输出 0。因此 !0 = 1 且 !234 = 0。第二个 ! 简单地切换输出,使 0 变为 1,1 变为 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.

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

回答by Cheers and hth. - Alf

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

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

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

我从其他答案和评论中看到,很多人不熟悉这个习语在 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]
> _

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.

至少有一个人认为,如果一个彻头彻尾的新手不认识它的含义,那就不好了。嗯,这很愚蠢。有很多完全是新手不认识或不理解的。编写一个代码以便任何新手都能理解它并不是专业人士的事情。甚至不适合学生。从排除完全新手不认识的运算符和运算符组合的路径开始......好吧,我没有词来给这种方法一个适当的描述,抱歉。

回答by kallitokaco

The answer of user143506 is correct but for a possible performance issue I compared the possibilies in asm:

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

return x;, return x != 0;, return !!x;and even return boolean_cast<bool>(x)results in this perfect set of asm instructions:

return x;, return x != 0;,return !!x;甚至return boolean_cast<bool>(x)产生了这组完美的 asm 指令:

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

这已针对 GCC 7.1 和 MSVC 19 2017 进行了测试。(只有 MSVC 19 2017 中的 boolean_converter 导致更多的 asm 代码,但这是由模板化和结构引起的,从性能的角度来看可以忽略不计,因为相同上面提到的行可能只是为具有相同运行时的不同函数重复。)

This means: There is no performance difference.

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

PS: This boolean_cast was used:

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

回答by Learner

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

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

for compiler in the end it wont make difference .

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

回答by Alan

I've never like this technique of converting to a booldata type - it smells wrong!

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

Instead, we're using a handy template called boolean_castfound here. It's a flexible solution that's more explicit in what it's doing and can used as follows:

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

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