标准在哪里定义volatile变量可以更改 未被发现?
我发现了两个关于volatile的规范性文本:
读取由 volatile glvalue ([basic.lval])指定的对象,修改对象,调用库I / O函数或调用执行任何这些操作的函数都是副作用,即执行环境状态的变化。对表达式(或子表达式)的评估通常包括值计算(包括确定对象的身份以进行glvalue评估和获取先前分配给对象的值以进行prvalue评估)和副作用的初始化。 >。当返回对库I / O函数的调用或评估通过易失性glvalue进行的访问时,即使该调用或volatile访问所隐含的某些外部操作(例如I / O本身)也被认为是完全的副作用。可能尚未完成。
本段是否涉及未发现的更改? 副作用可能意味着这个吗?
或者有dcl.type.cv/5:
通过易失性glvalue进行访问的语义是实现定义的。如果尝试通过使用非易失性glvalue来访问用volatile限定类型定义的对象,则行为是不确定的。
此段是关于我的问题吗? “通过易失性glvalue进行访问的语义是实现定义的”到底是什么意思?您可以举一个不同的“访问语义”的例子吗?
还有dcl.type.cv/6,这是关于我的问题,但这只是一个注释:
[注:volatile是实现的一种暗示,以避免涉及对象的积极优化,因为对象的值可能通过实现无法检测到的方式进行更改。此外,对于某些实现,volatile可能指示需要特殊的硬件指令才能访问该对象。有关详细的语义,请参见[intro.execution]。通常,volatile的语义在C ++中的意图与在C语言中是相同的。— —“ end note]
答案 0 :(得分:7)
这里的关键是“执行环境状态的改变”。
执行环境是程序外部的内容。这可能包括操作系统,文件系统,屏幕等。通常是不可预测的。您不能假设如果向文件写入0,则该文件不会被另一个带有1的进程覆盖。
volatile
变量在逻辑上是该执行环境的一部分。就C ++而言,环境可以像枚举文件一样枚举,读取和写入它们。这可能在您的程序不知道的情况下发生。
另一方面,您的实现实现了程序与其执行环境之间的链接,因此它确实对可能发生的事情有所了解。如果它具有某种专用的RAM磁盘实现,则它可能知道某些文件名在OS文件系统中不可见。并且它可能知道volatile int i
位于CPU寄存器中,因此无法通过内存映射对其进行访问。这是C ++标准所允许的。它只是一般性地谈论执行环境,实现必须更加精确。这就是“实现定义的语义”的含义。
答案 1 :(得分:1)
volatile
只是对编译器的请求,要求编译器为每次访问从内存中重新加载变量。它适用于2个常见用例:
一旦您知道,该标准中不同的引号都是有意义的。
读取由易失性glvalue([basic.lval])指定的对象,...都是副作用,它们是执行环境状态的变化。
读取硬件寄存器可能会对底层系统产生影响,这就是为什么它被认为是可观察到的副作用的原因。
通过易失性glvalue进行访问的语义是实现定义的。如果尝试通过使用非易失性glvalue来访问用volatile限定类型定义的对象,则行为是不确定的。
如果使用非易失性指针访问易失性硬件寄存器,则编译器可以缓存先前的值,而不执行物理访问。
[注:volatile是实现的一种暗示,以避免涉及对象的积极优化,因为对象的值可能通过实现无法检测到的方式进行更改。此外,对于某些实现,volatile可能指示需要特殊的硬件指令才能访问该对象。有关详细的语义,请参见[intro.execution]。通常,volatile的语义在C ++中的意图与在C语言中是相同的。— —“ end note]
某些实现可以为特殊的低级io端口操作保留一个存储区。在这种情况下,可能需要使用volatile
说明符和该特殊存储区地址的组合才能通过特殊的io操作验证转换或正常的内存访问操作。