C++ 中的双重否定
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/248693/
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
Double Negation in C++
提问by Brian Gianforcaro
I just came onto a project with a pretty huge code base.
我刚刚开始了一个具有相当庞大代码库的项目。
I'm mostly dealing with C++ and a lot of the code they write uses double negation for their boolean logic.
我主要处理 C++ 并且他们编写的许多代码对其布尔逻辑使用双重否定。
if (!!variable && (!!api.lookup("some-string"))) {
do_some_stuff();
}
I know these guys are intelligent programmers, it's obvious they aren't doing this by accident.
我知道这些人都是聪明的程序员,很明显他们这样做不是偶然的。
I'm no seasoned C++ expert, my only guess at why they are doing this is that they want to make absolutely positive that the value being evaluated is the actual boolean representation. So they negate it, then negate that again to get it back to its actual boolean value.
我不是经验丰富的 C++ 专家,我对他们为什么这样做的唯一猜测是他们想要绝对肯定被评估的值是实际的布尔表示。所以他们否定它,然后再次否定它以使其恢复为实际的布尔值。
Is this correct, or am I missing something?
这是正确的,还是我错过了什么?
采纳答案by Don Neufeld
It's a trick to convert to bool.
转换为 bool 是一个技巧。
回答by Tom Barta
It's actually a very useful idiom in some contexts. Take these macros (example from the Linux kernel). For GCC, they're implemented as follows:
在某些情况下,它实际上是一个非常有用的习语。以这些宏为例(来自 Linux 内核的示例)。对于 GCC,它们的实现方式如下:
#define likely(cond) (__builtin_expect(!!(cond), 1))
#define unlikely(cond) (__builtin_expect(!!(cond), 0))
Why do they have to do this? GCC's __builtin_expect
treats its parameters as long
and not bool
, so there needs to be some form of conversion. Since they don't know what cond
is when they're writing those macros, it is most general to simply use the !!
idiom.
为什么他们必须这样做?GCC__builtin_expect
将其参数视为long
and not bool
,因此需要进行某种形式的转换。由于他们cond
在编写这些宏时不知道是什么,因此最常用的是简单地使用!!
习语。
They could probably do the same thing by comparing against 0, but in my opinion, it's actually more straightforward to do the double-negation, since that's the closest to a cast-to-bool that C has.
他们可能可以通过与 0 进行比较来做同样的事情,但在我看来,做双重否定实际上更直接,因为这是 C 所具有的最接近于 cast-to-bool 的。
This code can be used in C++ as well... it's a lowest-common-denominator thing. If possible, do what works in both C and C++.
这段代码也可以用在 C++ 中……这是一个最低公分母的东西。如果可能,请执行在 C 和 C++ 中都有效的操作。
回答by fizzer
The coders think that it will convert the operand to bool, but because the operands of && are already implicitly converted to bool, it's utterly redundant.
编码人员认为它会将操作数转换为bool,但由于&&的操作数已经隐式转换为bool,因此完全多余。
回答by Richard Harrison
It's a technique to avoid writing (variable != 0) - i.e. to convert from whatever type it is to a bool.
这是一种避免写入(变量!= 0)的技术 - 即从任何类型转换为布尔值。
IMO Code like this has no place in systems that need to be maintained - because it is not immediately readable code (hence the question in the first place).
像这样的 IMO 代码在需要维护的系统中没有位置 - 因为它不是立即可读的代码(因此首先是问题)。
Code must be legible - otherwise you leave a time debt legacy for the future - as it takes time to understand something that is needlessly convoluted.
代码必须清晰易读——否则你会为未来留下时间债务——因为理解不必要的复杂事物需要时间。
回答by jwfearn
Yes it is correct and no you are not missing something. !!
is a conversion to bool. See this questionfor more discussion.
是的,这是正确的,不,您没有错过任何东西。 !!
是到 bool 的转换。有关更多讨论,请参阅此问题。
回答by RobH
It side-steps a compiler warning. Try this:
它回避了编译器警告。尝试这个:
int _tmain(int argc, _TCHAR* argv[])
{
int foo = 5;
bool bar = foo;
bool baz = !!foo;
return 0;
}
The 'bar' line generates a "forcing value to bool 'true' or 'false' (performance warning)" on MSVC++, but the 'baz' line sneaks through fine.
'bar' 行在 MSVC++ 上生成一个“强制值为 bool 'true' 或 'false'(性能警告)”,但 'baz' 行很好地潜入。
回答by KarlU
Legacy C developers had no Boolean type, so they often #define TRUE 1
and #define FALSE 0
and then used arbitrary numeric data types for Boolean comparisons. Now that we have bool
, many compilers will emit warnings when certain types of assignments and comparisons are made using a mixture of numeric types and Boolean types. These two usages will eventually collide when working with legacy code.
传统的C开发人员没有布尔类型,所以他们经常#define TRUE 1
和#define FALSE 0
再使用任意的数字数据类型布尔比较。现在我们有了bool
,当使用数字类型和布尔类型的混合进行某些类型的赋值和比较时,许多编译器会发出警告。在处理遗留代码时,这两种用法最终会发生冲突。
To work around this problem, some developers use the following Boolean identity: !num_value
returns bool true
if num_value == 0
; false
otherwise. !!num_value
returns bool false
if num_value == 0
; true
otherwise. The single negation is sufficient to convert num_value
to bool
; however, the double negation is necessary to restore the original sense of the Boolean expression.
为了解决这个问题,一些开发人员使用以下布尔标识:!num_value
return bool true
if num_value == 0
; false
除此以外。!!num_value
返回bool false
如果num_value == 0
; true
除此以外。单个否定足以转换num_value
为bool
; 然而,双重否定是恢复布尔表达式的原始意义所必需的。
This pattern is known as an idiom, i.e., something commonly used by people familiar with the language. Therefore, I don't see it as an anti-pattern, as much as I would static_cast<bool>(num_value)
. The cast might very well give the correct results, but some compilers then emit a performance warning, so you still have to address that.
这种模式被称为惯用语,即熟悉该语言的人常用的东西。因此,我并不像我那样认为它是一种反模式static_cast<bool>(num_value)
。强制转换很可能会给出正确的结果,但是一些编译器随后会发出性能警告,因此您仍然必须解决这个问题。
The other way to address this is to say, (num_value != FALSE)
. I'm okay with that too, but all in all, !!num_value
is far less verbose, may be clearer, and is not confusing the second time you see it.
解决这个问题的另一种方法是说,(num_value != FALSE)
. 我也同意,但总而言之,!!num_value
它没有那么冗长,可能更清晰,并且第二次看到它时不会感到困惑。
回答by Marcin
Is operator! overloaded?
If not, they're probably doing this to convert the variable to a bool without producing a warning. This is definitely not a standard way of doing things.
是运营商!超载?
如果没有,他们可能这样做是为了将变量转换为 bool 而不会产生警告。这绝对不是标准的做事方式。
回答by chux - Reinstate Monica
!!
was used to cope with original C++ which did not have a boolean type (as neither did C).
!!
用于处理没有布尔类型的原始 C++(C 也没有)。
Example Problem:
示例问题:
Inside if(condition)
, the condition
needs to evaluate to some type like double, int, void*
, etc., but not bool
as it does not exist yet.
在 内部if(condition)
,condition
需要评估为某种类型,例如double, int, void*
等,但不是bool
因为它尚不存在。
Say a class existed int256
(a 256 bit integer) and all integer conversions/casts were overloaded.
假设存在一个类int256
(一个 256 位整数)并且所有整数转换/强制转换都已重载。
int256 x = foo();
if (x) ...
To test if x
was "true" or non-zero, if (x)
would convert x
to some integer and thenassess if that int
was non-zero. A typical overload of (int) x
would return only the LSbits of x
. if (x)
was then only testing the LSbits of x
.
要测试x
是“真”还是非零,if (x)
将转换x
为某个整数,然后评估它是否int
为非零。的典型重载(int) x
将仅返回 的 LSbits x
。 if (x)
然后只测试 的 LSbits x
。
But C++ has the !
operator. An overloaded !x
would typically evaluate all the bits of x
. So to get back to the non-inverted logic if (!!x)
is used.
但是 C++ 有!
操作符。重载!x
通常会评估 的所有位x
。所以要回到使用非反转逻辑if (!!x)
。
回答by Joshua
If variableis of object type, it might have a ! operator defined but no cast to bool (or worse an implicit cast to int with different semantics. Calling the ! operator twice results in a convert to bool that works even in strange cases.
如果变量是对象类型,它可能有一个 ! 运算符已定义但未强制转换为 bool(或者更糟的是隐式强制转换为具有不同语义的 int。两次调用 ! 运算符会导致转换为 bool,即使在奇怪的情况下也能正常工作。