c预编译器对定义为(void)0的宏做了什么

时间:2014-07-29 17:07:03

标签: c macros compiler-construction

我有一些基于编译器标志定义的宏。我正在尝试决定是否要将宏定义为(void)0或将其定义为未定义并导致编译时错误。

#ifdef DEBUG
  #define PRINTF(...) printf(__VA_ARGS__)
#else
  #define PRINTF(...) (void)0
#endif

int main(void) {
  ...
  PRINTF("something");
  ...
}

VS

#ifdef DEBUG
  #define PRINTF(...) printf(__VA_ARGS__)
#endif

int main(void) {
  ...
  #ifdef DEBUG
    PRINTF("something");
  #endif
  ...
}

我不确定我喜欢哪种技术。一方面用#ifdef包装每个PRINTF语句都很难看。另一方面,如果我调用了一个在上下文中不起作用的函数,那么在编译时就知道了。

我认为决定因素是(void)0宏是否会影响可执行文件的大小。

编译代码时,(void)0会发生什么?如果PRINTF被定义为(void)0,那是否意味着可执行文件将包含某种(void)0指令或是否会被完全忽略?

3 个答案:

答案 0 :(得分:7)

(void) 0;

是一个没有副作用的表达式语句。任何理智的实现都会优化这个语句(实现可以用这样的语句做什么?)。

(void) 0作为宏定义,如果定义assert,则由{C11} 7.2p1中NDEBUG宏定义中的C标准认可:

#define assert(ignore) ((void)0)

请注意定义:

#define PRINTF(...) (void)0

而不是

#define PRINTF(...)

有优势。在第一种情况下,您有一个表达式(就像一个不返回值的函数),因此它可用于例如逗号表达式或条件表达式中。

例如:

// Comma expression
printf("test"), PRINTF("Hi Dennis");

// Conditional expression
test-expr ? perror("Hello") : PRINTF("world");

这两个表达式语句仅对前PRINTF定义((void) 0)有效。

答案 1 :(得分:5)

它将被完全忽略,您可以通过查看程序集输出(gcc -S将生成file.s,asm输出)来确认这一点,比较是否有(void)0行和看到它完全一样。

答案 2 :(得分:1)

中间正常的编译器将优化掉死(无法访问)代码,因此您可以:

  #ifdef DEBUG
  #define PRINTF(...) if (1) { printf(__VA_ARGS__) ; }
  #else
  #define PRINTF(...) if (0) { printf(__VA_ARGS__) ; }
  #endif

它具有允许编译器检查调试代码的巨大优势,无论您是否正在使用/不启用DEBUG - 这样可以降低在您的牙齿痕迹中留下痛苦痕迹的风险背面。