为什么(void)0在C和C ++中没有任何操作?
我已经看到在glibc中debuggingprintf,如果定义了NDEBUG ,它在内部被定义为(void) 0
。 同样,Visual C ++编译器的__noop
那里。 前者适用于GCC和VC ++编译器,后者仅适用于VC ++。 现在我们都知道,上述两个语句都将被视为无操作,并且不会生成相应的代码; 但是这里是我有疑问的地方。
在__noop
情况下,MSDN表示这是编译器提供的内部函数。 来(void) 0
0〜为什么编译器解释为没有操作? 这是C语言的一个棘手的用法还是标准说明了一些关于它的意义? 或者甚至这与编译器实现有关?
(void)0
(+ ;
)是一个有效的,但是“什么都不做”的C ++expression式,就是一切。 它不会转换为目标体系结构的no-op
指令,只要语言期望完整语句(例如作为跳转标签的目标或if
子句的主体),它就是占位符的空语句。
编辑:(更新根据克里斯Lutz的评论)
应该指出的是,当作为一个macros使用,说
#define noop ((void)0)
(void)
防止它被意外地用作值
int x = noop;
对于上面的expression式,编译器会正确地将其标记为无效操作。 海湾合作委员会吐出error: void value not ignored as it ought to be
和VC ++吠叫'void' illegal with all types
。
任何没有任何副作用的expression式都可以被编译器视为无操作,而不必为其生成任何代码(尽pipe可能)。 恰恰是,编译(而不是使用结果)对于编译器(和人类)来说很容易看到没有副作用。
我想你说的是glibc ,而不是glib ,而macros观问题就是assert
:
在glibc的<assert.h>
,定义了NDEBUG
(不debugging), assert
被定义为:
#ifdef NDEBUG #if defined __cplusplus && __GNUC_PREREQ (2,95) # define __ASSERT_VOID_CAST static_cast<void> #else # define __ASSERT_VOID_CAST (void) #endif # define assert(expr) (__ASSERT_VOID_CAST (0)) #else /* more code */ #endif
这基本上意味着assert(whatever);
相当于((void)(0));
,什么都不做。
从C89标准(4.2节):
头文件
<assert.h>
定义了assert
macros,并引用另一个macros,NDEBUG
这不是由
<assert.h>
定义的。 如果在包含<assert.h>
的源文件中的NDEBUG
被定义为一个macros名,assert
macros被定义为#define assert(ignore) ((void)0)
我不认为定义debugging打印macros等于(void)0
是很有道理的。 你能告诉我们在哪里完成了吗?
即使如此,为什么types将其废弃? 此外,在#define dbgprintf(void)0的情况下,它被称为dbgprintf(“Hello World!”)。 – >(void)0(“Hello World!”); – 这是什么意思? – 传奇2k
macros用别的东西代替你的代码,所以如果你#debine dbgprint(接受x)为
void(0)
那么不会重写X,所以dbgprintf(“Helloworld”)不会被转换为(void)0(“Hello world”),而是(void)0; – 不仅macros名dbgprint被replace为(void)0,而且整个调用dbgprintf(“…”)
在Windows上,我在Main.cpp中尝试一些这样的代码:
#include <iostream> #define TRACE ((void)0) int main() { TRACE("joke"); std::cout << "ok" << std::endl; return 0; }
然后,我用Main.i输出构buildRelease版本的exe文件。 在Main.i文件中,TRACEmacros被replace为: ((void)0)("joke")
,并且visual studio给出警告:“警告C4353:使用非标准扩展:常量0作为函数expression式使用'__noop'function内在而不是“。 运行exe文件,控制台打印出“ok”字符。 所以我认为一切都很清楚:根据c ++语法,macrosTRACE [#define TRACE((void)0)]的定义是非法的,但Visual Studio的c ++编译器支持这种行为作为编译器扩展。 所以我的结论是:[#define TRACE((void)0)]是非法的c ++语句,你最好不要使用这个。 但是[#define TRACE(x)((void)0)]是法律声明。 就这样。