【问题标题】:casting 0 to void将 0 转换为 void
【发布时间】:2011-10-23 13:57:55
【问题描述】:

在我的 C++ 实现(Visual Studio 2008 实现)中,我在 <cassert> 中看到以下行

#ifdef  NDEBUG
#define assert(_Expression) ((void)0)

我不明白需要将 0 强制转换为 void。在我看来,

#ifdef  NDEBUG
#define assert(_Expression) (0)

甚至干脆

#ifdef  NDEBUG
#define assert(_Expression) 0

可以,考虑到可以使用assert(expr) 的上下文。

那么,在这种情况下,int 类型的 0 而不是 void 类型的 0 有什么危险呢?有任何现实示例吗?

【问题讨论】:

  • 顺便说一句,虽然这对许多人来说似乎是一个微不足道的问题,但实际上我偶尔会遇到经验不足的程序员问这个话题。它类似于(但不是重复)关于为什么宏通常包含在 do ... while(0) 构造中的问题。有时,一个人的“太明显而不会被打扰”是另一个人的“WTF?!?”。

标签: c++ c macros void


【解决方案1】:

复杂表达式(void)0 的唯一目的是避免编译器警告。如果你只是有一个赤裸裸的、无用的表达式,编译器可能会警告一个无效的表达式。但是,通过明确地将某些内容转换为 void,您表明您打算这样做。

(想想如果编译器突然说“警告:表达式0;没有效果。”,当你所做的只是切换到发布模式时,用户会有多困惑。)

这也是 C 中的常见做法,您可以说 (void)printf("Hello"); 告诉编译器您有意选择忽略函数的返回值。

(void) 演员表不仅仅是特定实现的选择;它是 C 标准所要求的。引用 2011 ISO C 标准(类似的措辞出现在 1990 和 1999 版本中):

如果NDEBUG被定义为源文件中的宏名 其中 <assert.h> 被包括在内,assert 宏被简单地定义为

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

C++ 标准要求 <cassert> 标头的内容与标准 C <assert.h> 标头的内容相同。

【讨论】:

  • assert 的上下文中这样做还有另一个原因:它确保“foo = assert(blurf);”在调试和发布模式下都会引发编译时错误。
  • Curiosum:在 C++ 模式的 GCC 中,我们有 static_cast<void>。整洁。
  • 它不生成代码并且还抑制警告是正确的,但真正的问题是为什么不只是#define assert(ignore)。我唯一的猜测是一些编译器不喜欢空语句。
  • @Gene:与 Zack 所说的原因相同——它防止了断言语句的误用,并且避免了关于裸分号的警告。
  • 不要忘记,assert() 需要按照标准扩展“到空表达式”。我确信标准中的要求与这里的许多 cmets 一致。但就特定实现而言,这就是所有必要的基本原理。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-10-24
  • 1970-01-01
  • 1970-01-01
  • 2018-02-24
  • 1970-01-01
  • 2020-06-24
  • 1970-01-01
相关资源
最近更新 更多