我们刚刚发现某个编译器(Greenhills)将以下构造视为错误:
// local variable
mytype x;
...
((void) (x));
编译器报告:
error #549-D: variable "x" is used before its value is set
。
我们在特殊情况下使用此类构造,以避免与根本未使用的变量相关的编译器警告。我们想测试该类型是否真的存在,所以这完全是有意为之。
然而,我的问题与该编译器的行为方式有关。根据什么 C 标准规则,编译器决定强制转换为 void(实际上应该在汇编代码中转换为空)实际上是在“使用”变量?
C 标准 C17 6.3.2.2。说道:
void 表达式(具有类型
的表达式)的(不存在的)值不应 以任何方式使用,并且隐式或显式转换(除了void
)不得 应用于这样的表达式。如果任何其他类型的表达式被计算为 void 表达式,其值或指示符被丢弃。 (对 void 表达式进行求值 副作用。)void
所以大多数时候这个表达方式根本不被使用。然而,括号中的最后一句话很有趣 - 评估副作用意味着例如如果您有一个函数作为操作数,则该函数将被执行。或者,如果您有一个
volatile
限定变量,编译器必须计算该表达式。 (void)my_volatile;
是否应该被视为读取访问一直是个模糊的问题。
我们可以肯定地说,如果
mytype
不涉及 volatile
那么编译器就会感到困惑,应该丢弃整行。但如果是 volatile
那么可能涉及读取访问。
然而编译器仍然不应该对
volatile
是否已初始化做出任何假设,因为volatile
的定义就是变量可能会在编译器无法控制的情况下随时发生变化。所以它仍然是一个不正确的诊断消息。
我会将其报告为编译器诊断错误,因为强制转换为
void
是常见的 C 习惯用法。
在即将推出的 C23 中,您将能够将变量声明为
[[maybe_unused]] mytype x;
,这也应该消除编译器警告。