这将是一篇很长的文章,为了将其置于上下文中并提供尽可能多的信息,我必须浏览各种链接和引用 - 这通常是我们进入 C/C++ 标准兔子洞的唯一方法。如果您对这篇文章有更好的引用或任何其他改进,请告诉我。但先总结一下,你可以责怪@zwol对我来说发布这个;-) https://stackoverflow.com/questions/38230856/is-the-definition-of-volatile-this-volatile-or-is-gcc-having-some-standard-co#comment63893828_38231071_目的是从两个命题中找出真相:
- C 和(通过导入;参见注释)C++ 标准要求通过
volatile *
or volatile &
必须引用最初声明的对象volatile
为了有volatile
语义?
- Or 正在访问一个非
volatile
- 合格的对象通过volatile
指针/引用足以/应该使所述访问的行为就像声明了对象一样volatile
?
不管怎样,如果(看起来)措辞与意图相比有些模糊——我们可以说清楚吗在标准本身中?
第一种相互排斥的解释更为普遍,这并非完全没有根据。然而,我希望表明,存在大量支持第二点的“合理怀疑”——尤其是当我们回顾基本原理和工作组文件中的一些先前段落时。
公认的智慧:所引用的对象本身必须已声明volatile
昨天的热门问题“不稳定”的定义是否如此不稳定,或者 GCC 是否存在一些标准合规性问题? https://stackoverflow.com/questions/38230856通过假设出现volatile
参考将赋予volatile
行为在非volatile
所指的——但发现它没有,或者在不同程度上以不可预测的方式发生了。
接受的答案最初得出的结论是,只有所声明的引用类型才重要。这和大多数评论似乎都同意,正如我们所熟知的,等效原则正在发挥作用const
:行为只会是volatile
(或根本定义)如果引用具有相同的cv- 被推荐对象的资格:
该段落中的关键词是对象。volatile sig_atomic_t flag;
是一个易失性对象。*(volatile char *)foo
仅仅是通过易失性限定的左值进行访问,并且标准不要求具有任何特殊效果. – zwol https://stackoverflow.com/users/388520/zwol
这种解释似乎被广泛接受,正如对这个类似但希望不重复的问题的答复所示:指向非易失性对象的易失性指针的行为要求 https://stackoverflow.com/questions/28654418/requirements-for-behavior-of-pointer-to-volatile-pointing-to-non-volatile-object但即便如此,也存在不确定性:在答案说“不”之后,它又说“也许”!无论如何……让我们检查一下标准,看看“不”的依据是什么。
标准说了什么...或没有说什么
C11, N1548,§6.7.3: 而很明显访问一个对象是UB定义为 volatile
or const
通过不共享所述限定符的指针进行类型...
6如果尝试修改用 a 定义的对象const
- 通过使用带有非的左值来限定类型const
-限定类型,行为未定义。如果试图参考用 a 定义的对象volatile
-合格类型通过使用非左值volatile-
限定类型,行为未定义。(133)
...该标准似乎没有明确提到相反的情况,即volatile
。另外,在总结的时候volatile
及其操作,现在讨论一个对象has volatile
-合格类型:
7 An 对象具有volatile
-合格类型可能会以实现方式未知的方式进行修改或具有其他未知的副作用。因此,引用此类对象的任何表达式都应严格根据抽象机的规则进行评估,如 5.1.2.3 中所述。此外,在每个序列点,最后存储在对象中的值应与抽象机规定的值一致,除非被前面提到的未知因素修改。(134)什么构成对具有volatile
-限定类型是实现定义的。
我们是否假设“has”等同于“被定义为”?或者可以“有” http://1.bp.blogspot.com/-CzqzzBV2tMk/TxBM3ar18MI/AAAAAAAAPm0/6faLPO9BM8w/s1600/i-can-has-cheezburger.jpg引用对象和引用限定符的组合?
一位评论者用这样的措辞很好地总结了这个问题:
From n1548§6.7.3 ¶6 该标准使用短语“使用易失性限定类型定义的对象”来区分它与“具有易失性限定类型的左值”。不幸的是,这种“定义的对象”与“左值”的区别没有继续下去,然后标准使用“具有 volatile 限定类型的对象”,并表示“什么构成对具有 volatile 限定类型的对象的访问”是实现定义的”(为了清楚起见,可以说“左值”或“定义的对象”)。那好吧。 –迪特里希·埃普 https://stackoverflow.com/users/82294/dietrich-epp
同一部分的第 4 段似乎很少被引用,但很可能是相关的,我们将在下一节中看到。
合理怀疑:是/曾经是volatile
旨在赋予的指针/引用volatile
其取消引用的语义?
上述答案有一个评论,其中作者引用了委员会早些时候的声明,对“参考必须匹配所指”的想法提出了质疑:
有趣的是,里面有一句话[C99 基本原理volatile
] 这意味着委员会meant for *(volatile T*)x
强制该人访问x
被视为挥发性的;但标准的实际措辞并没有达到这一点。 – 兹沃尔
我们可以从上述第二个线程中找到有关这一基本原理的更多信息:指向非易失性对象的易失性指针的行为要求 https://stackoverflow.com/questions/28654418/requirements-for-behavior-of-pointer-to-volatile-pointing-to-non-volatile-object
另一方面,这个帖子 http://bytes.com/topic/c/answers/221923-cast-volatile引用《国际标准的基本原理——编程语言——C》的 6.7.3:
将值强制转换为限定类型没有任何效果;资格
(例如,易失性)不会对访问产生任何影响,因为它已经发生
在案件发生之前。如果需要访问非易失性对象
使用易失性语义,该技术是将地址转换为
对象到适当的指针限定类型,然后取消引用
那个指针。
—philipxy
并从那个字节线程 http://bytes.com/topic/c/answers/221923-cast-volatile,我们称为 C99 s6.7.3 p3 - 又名 C11 的 p4 - 以及此分析:
该段落位于理由文件第 6.7.3.1 节之前。如果您还需要引用标准文档本身,请引用6.7.3 p3:
与限定类型关联的属性仅对左值表达式有意义。
表达方式(volatile WHATEVER) non_volatile_object_identifier
is not左值,因此“易失性”限定符毫无意义。
相反,表达式* (volatile WHATEVER *) & non_volatile_object_identifier
is左值(它可以放在赋值语句的左侧),因此 'volatile' 限定符的属性在这种情况下具有其预期含义。
—蒂姆·伦奇
有一个very支持这一想法的具体论证,特别是关于第一个相关问题,工作组论文N1381 http://open-std.org/jtc1/sc22/wg14/www/docs/n1381.pdf。本文介绍了附件memset_s()
做OP想要的事情 - 保证内存的非省略填充。在讨论可能的实现时,它似乎支持这样的想法 - 通过省略陈述任何要求 - 使用volatile
改变非指针volatile
object should根据生成代码指针的限定符,无论所引用的对象是什么......
- 独立于平台的“secure-memset”解决方案:
void *secure_memset(void *v, int c , size_t n) {
volatile unsigned char *p = v;
while (n--) *p++ = c;
return v;
}
这种方法将防止内存清理被优化掉,并且它应该可以在任何符合标准的平台上运行。
...并且注意编译器不这样做...
最近有通知称一些编译器不总是遵守标准而违反了标准volatile
预选赛。
谁是对的?
那太累了。这里当然有很大的解释空间,具体取决于您碰巧读过哪些文档,哪些没有读过,以及您选择如何解释许多不够具体的单词。显然有些地方出了问题:要么:
- 基本原理和 N1381 的措辞错误或随意,或者
- 它们被特别追溯无效......或
- 该标准的措辞错误或随意。
我希望我们能够比过去围绕此事的所有含糊和猜测做得更好,并得到一份更结论性的声明记录在案。为此,我们非常欢迎专家提供任何进一步的资料和想法。