宏定义中双重否定的目的是啥,例如 (!!(expr))? [复制]
Posted
技术标签:
【中文标题】宏定义中双重否定的目的是啥,例如 (!!(expr))? [复制]【英文标题】:What is the purpose of a double negative in macro definition, like (!!(expr))? [duplicate]宏定义中双重否定的目的是什么,例如 (!!(expr))? [复制] 【发布时间】:2011-02-05 23:08:26 【问题描述】:可能重复:Double Negation in C++ code.
我正在阅读代码库,并找到类似这样的内容:
#define uassert(msgid, msg, expr) (void)((!!(expr))||(uasserted(msgid, msg), 0))
我不明白为什么使用 (!!(expr)) 而不是单个 (expr)。无论如何,双重否定意味着积极,不是吗?我错过了什么吗?
【问题讨论】:
我什至无法弄清楚这段代码的目的是什么! ;) 就像 R 说的,这里完全没用。 正如您自己正确指出的那样,在这种情况下它是多余的。也许它只是为了避免一些编译器警告而添加的。 @AndersK。你说的对。它可能是为了满足某些编译器而添加的。正如@R 和@GMan 指出的那样,虽然这是一种强制进行布尔对话的方法,但这里不需要 !! 技巧。因为它已经在布尔上下文中。我现在很清楚了。谢谢。 '-' 是否定的; '!'不是。 “消极”和“积极”在这里不适用。使用不正确的术语会造成混乱。 【参考方案1】:这是一种将表达式转换为布尔值的方法。但在 C++ 中,运算符!可以超载。 C/C++ 的另一种方式:
0 != (expr)
C++ 唯一方法:
static_cast<bool>(expr)
[编辑]
更多地考虑 C++ 运算符重载,避免使用运算符是有意义的。 Boost.Spirit 和 Boost.Lambda 之类的库使用表达式模板和惰性求值,因此 (expr) || call()
之类的表达式的行为可能与预期不同。该宏最防弹的版本如下所示:
#define uassert(expr) if(expr) else uasserted(...);
这里只使用了expr
到布尔值的转换。需要else
分支来防止uassert(x) else something_else();
之类的表达式。
【讨论】:
接受这个答案,因为@Maxim 给出了解释和进一步的知识。 现在uassert(expr)
不再是一个表达式;这是一个声明。这极大地限制了您可以使用它的地方。如果你想投射到bool
,只需投射到bool
。
这是一个断言表达式,我假设它的值在调试版本中为 bool 类型,在发布中为 void。你能证明它对使用的限制有多大吗?
它不是“断言表达式”,因为它由if-else
语句组成。【参考方案2】:
它只会确保宏的 expr 部分被转换为布尔值。
【讨论】:
@GMan,通常是的,但也许不是。可能没有到bool
的隐式转换,但有一个重载的否定。
@Steven:写这样一个类的人是个白痴。抱歉,我的做法并非基于愚蠢的人可能写的内容。
@GMan:很可能就是这样。尽管如此,这种区别是内置在语言中的。【参考方案3】:
这是 C++ 中有时用于转换为布尔类型的习语。
【讨论】:
【参考方案4】:在您向我们展示的示例中,!!
完全没用。但是,一般来说,它用作 C99 之前的粗略,相当于转换为 _Bool
,即 0 保持为 0,任何其他值变为 1。
【讨论】:
!!
并不是完全没用。如果||
是重载运算符,(expr) || uasserted(...)
在 C++ 中可能无法正常工作。这就是为什么 (expr) 必须首先显式转换为布尔值的原因。
谢谢你提醒我为什么我讨厌运算符重载的语言(或者至少那些应该有固定定义的运算符可以重载)。
@Maxim:糟糕的推理。注意:如果!
是重载运算符,!!
在 C++ 中可能无法按预期工作。您的论点是弄巧成拙的:是的,有人可能对操作员很愚蠢,您不能轻易忽略他们对您的职位也可以做同样的事情。对任何正统的程序都没用,谁在乎人们写的非正统废话?你的实践基于好的代码,所以你最终会有好的编程实践。以上是关于宏定义中双重否定的目的是啥,例如 (!!(expr))? [复制]的主要内容,如果未能解决你的问题,请参考以下文章