12

如果我调用具有 volatile 参数的函数并且未使用该参数,那么编译器是否仍必须生成该参数?

void consume( volatile int ) { }

...

consume( some_expr );

GCC 确实尊重这一点,但我不确定标准中 volatile 的措辞是否需要这一点。在我看来,GCC 正在做正确的事情——这在逻辑上是对 volatile 变量的赋值,因此不应省略(根据 c++ 标准的 1.9-8)

注意:这样做的目的是防止优化器删除代码的评估。也就是说,它强制some_expr进行评估。它允许优化表达式,但确保它实际执行。

如果有任何差异,我已经将 C 和 C++ 添加为标签,作为我感兴趣的答案。不过我不认为会有。

回答: 我选择了第一个,因为我相信它是该标准的正确实际实现。然而,史蒂夫的哲学观点非常有趣,实际上可能意味着标准是模棱两可的。

4

2 回答 2

5

的未命名参数consume无法读取,因为它未命名。但是,它已初始化,并且初始化(带有some_expr)是可见的副作用。因此编译器可能不会优化初始化。

这是否需要实际评估some_expr是另一回事。一般来说,这不是一个可见的副作用,但它可能是如果some_expr包含volatile子表达式。

[编辑] 请注意,“未命名”部分可能出现在两个地方。调用者通常无法知道参数是否已命名(更不用说使用了)例如

void consume( volatile int x);
consume( some_expr );
// other .cpp
void consume( volatile int ) { } // Same function.
于 2012-04-12T13:12:09.587 回答
1

有可能提出相反的论点,但我认为实现可能会省略对自动volatile对象的访问,前提是它们对程序没有任何影响,并且还禁止程序员观察堆栈(通过未映射或只读页面) ,调试器等),或者至少警告这样做不会总是产生您期望的效果。一个未命名的参数符合该描述。

原因是“as-if”规则谈到了可见的副作用,并说 volatile 访问是可见的副作用。但是如果程序本身不以任何方式依赖它们,那么标准就不会说对象实际上必须位于“堆栈上”。该标准允许它位于硬件提供的特殊内存位置,不能以任何方式读取,只能写入,写入对硬件没有物理影响。既然这是允许的,那么说“标准要求”这种无效的写入实际上继续进行似乎是荒谬的。怎么会有人知道?该标准不要求二进制文件中必须有指令来执行写入,它要求神奇的、不可读的秘密对象必须采用特定的值。如果我声称它有那个价值,你就不能证明我错了:-)

不可能编写一个依赖于实际发生的这种易失性访问的符合标准的程序,或者检测是否some_expr被评估。真的它在你和你的调试器之间,不管它是否被计算。我已经看到调试器出错了。

所以,我认为允许一个实现破坏它自己的调试器,就像它根本不允许提供一个工作调试器一样。我不立即明白为什么它会想要。在实践中,我希望将参数标记为 volatile 与将函数的定义移动到优化器找不到的地方具有大致相同的效果——它将确保可以使用该值。

于 2012-04-12T13:27:30.993 回答