为什么(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>定义了assertmacros,并引用另一个macros,

 NDEBUG 

这不是由<assert.h>定义的。 如果在包含<assert.h>的源文件中的NDEBUG被定义为一个macros名, assertmacros被定义为

 #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)]是法律声明。 就这样。