如果我调用一个具有volatile参数的函数,并且该参数未被使用,那么编译器是否必须生成参数?
void consume( volatile int ) { }
...
consume( some_expr );
海湾合作委员会确实对此表示敬意,但我不确定标准中的挥发性措辞是否需要这样做。在我看来,GCC做的是正确的 - 这在逻辑上是对volatile变量的赋值,因此不应该被省略(根据c ++标准的1.9-8)
注意:这样做的目的是阻止优化器删除代码评估。也就是说,它会强制some_expr
进行评估。它允许表达式进行优化,但确保它实际执行。
我已经添加了C和C ++作为标签作为答案,如果有任何差异,我会感兴趣。我不认为会有。
答案:我选择了第一个,因为我相信它是标准的正确实际实现。然而,史蒂夫的哲学观点非常有趣,实际上可能意味着标准是模棱两可的。
答案 0 :(得分: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.
答案 1 :(得分:1)
有可能反过来说,但我认为实现可能会省略对自动volatile
对象的访问,前提是它们对程序没有任何影响,并且还要求它禁止程序员观察堆栈(通过未映射或只读页面,调试器等),或者至少警告说这样做并不总是具有您期望的效果。未命名的参数符合该描述。
原因是“as-if”规则讨论了可见的副作用,并说挥发性访问是可见的副作用。但是如果程序本身并不以任何方式依赖它们,那么标准就不会说该对象必须实际上位于“堆栈”上。该标准允许它位于硬件提供的特殊存储单元中,不能通过任何方式读取,只能写入,写入它对硬件没有物理影响。由于这是允许的,因此说“标准要求”这种无效写入实际上是可行的似乎是荒谬的。怎么会有人知道?该标准并未强制要求二进制文件中必须有指令来执行写操作,它要求神奇的,不可读的秘密对象必须采用特定的值。如果我声称它有这个价值,你就无法证明我错了: - )
不可能编写一个依赖于实际发生的易失性访问的一致程序,或者检测some_expr
是否被评估。真的是你和你的调试器之间是否计算过。我已经看到调试器出错了。
所以,我认为实现允许打破自己的调试器,就像允许根本不提供有效的调试器一样。我不会立即明白为什么会这样。在实践中,我希望标记参数volatile与在优化程序无法找到它的位置移动函数的定义具有相同的效果 - 它将确保可以使用该值。