宏定义中双重否定的目的是啥,例如 (!!(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))? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

C宏定义中的连接符"##"和字符串化操作符"# "及变参宏"..."

可以定义 NSFound 宏吗?

UDS中的否定响应和肯定响应,已经CAN通讯中的特点

为啥双重否定强制值成为布尔值?

具有多行参数的宏功能?

OpenCV中的带参数宏定义CV_Assert()的作用