通过易失性引用/指针访问声明的非易失性对象是否会为所述访问赋予易失性规则?

2024-05-05

这将是一篇很长的文章,为了将其置于上下文中并提供尽可能多的信息,我必须浏览各种链接和引用 - 这通常是我们进入 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根据生成代码指针的限定符,无论所引用的对象是什么......

  1. 独立于平台的“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 的措辞错误或随意,或者
  • 它们被特别追溯无效......或
  • 该标准的措辞错误或随意。

我希望我们能够比过去围绕此事的所有含糊和猜测做得更好,并得到一份更结论性的声明记录在案。为此,我们非常欢迎专家提供任何进一步的资料和想法。


通过易失性引用/指针访问声明的非易失性对象是否会为所述访问赋予易失性规则?

volatile在 C 和 C++ 中并不意味着同样的事情。 C++ 标准使得通过易失性左值进行的访问变得可观察。 [1] 它表示它希望这与 C 行为相同。这就是 C 基本原理中描述的行为。尽管如此,C 标准表示对 volatile 声明的对象的访问是可观察的。 (请注意,通过非易失性左值访问易失性声明的对象是未定义的。)

However.有一个缺陷报告,基本上得到了委员会的同意(尽管仍然开放),该标准应该说,并且其意图一直是,并且实现总是反映出,重要的不是对象的波动性(根据标准),但访问(的左值)的波动性(根据基本原理)。

C11 版本 1.10 的缺陷报告摘要 日期:2016 年 4 月DR 476 http://www.open-std.org/jtc1/sc22/wg14/www/docs/summary.htm#dr_476左值的易失性语义 04/2016 Open

当然,对可观察行为所做的事情取决于实现。

确实没有任何歧义。只是人们不敢相信C 标准行为可能就是这样,因为这不是历史上的用法volatile(当地址文字左值被视为易失性对象时),如基本原理所预期的那样,如编译器之前和之后所实现的那样,如 C++ 标准所解释和描述的那样,如 DR 中所更正的那样。同样,该标准很明确,因为它没有说非易失性访问是可观察的,所以它们不是。 (“副作用”是定义评估偏序时使用的术语。)

[1] 或者至少希望现在是这样。来自评论下划线_d https://stackoverflow.com/users/2757035/underscore-d:

对于 C++,另请参阅P0612R0:注意 CH 2:易失性 http://open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0612r0.html, which 本月通过 https://isocpp.org/blog/2017/03/2017-03-post-kona-mailing-available清理 C++ 标准中一些关于“易失性对象”的剩余讨论,当真正通过易失性左值访问是它的含义(大概/希望是 C 的含义)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

通过易失性引用/指针访问声明的非易失性对象是否会为所述访问赋予易失性规则? 的相关文章

  • .crt 部分?这个警告是什么意思?

    我最近收到此警告 VC 2010 warning LNK4210 CRT section exists there may be unhandled static initializers or terminators 我假设这是关键部分
  • Dapper 在执行时挂起

    我有一个 IDb连接 sql UPDATE 表名 SET json json lastupdate SYSDATE WHERE id id var param new DynamicParameters param Add json jso
  • 为什么子函数不销毁GtkWindow?

    这是我的代码 void window first void enter window2 GtkWidget w gpointer data void quit GtkWidget w gpointer data void quit int
  • ASP.NET - 在 RenderContent 调用中将事件处理程序添加到 Repeater 内的 LinkBut​​ton

    我有一个加载自定义用户控件的 Sharepoint WebPart 用户控件包含一个 Repeater 而 Repeater 又包含多个 LinkBut ton 在 Web 部件的 RenderContent 调用中 我有一些用于添加事件处
  • Monotouch全局异常处理

    我在野外发现了一只令人讨厌的虫子 但我无法确定它的具体情况 有没有办法拥有全局 Try Catch 块 或者有办法处理 Monotouch 中未处理的任何异常 我可以包起来吗UIApplication Main args 在 try cat
  • 对作为函数参数传递的指针使用删除

    删除作为函数参数传递的指针是否可以 并且合法 如下所示 include
  • .NET 5 EF Core SaveChangesAsync 因错误而挂起

    尽管这个问题有很多结果 但没有一个真正给我明确的答案 每次我尝试通过 AddAsync 和 SaveChangesAsync 方法插入错误数据 例如重复的主键 时 我都会看到以下日志 执行 DbCommand 失败 15 毫秒 我还在 SQ
  • 如何让XmlReader读取C#中的属性?

    我有一个 XML Stream 其中包含以下 XML 内容
  • 如何从外语线程调用Python函数(C++)

    我正在开发一个程序 使用 DirectShow 来抓取音频数据 媒体文件 DirectShow 使用线程将音频数据传递给回调 我的程序中的函数 然后我让该回调函数调用另一个函数 Python 中的函数 我使用 Boost Python 来包
  • 如何在 C# 中更改公共 IP 地址

    我正在创建一个 C winform 应用程序 我想在其中更改公共 IP 地址 而不是像 Hotspot Shield ZenMate OpenVPN 等那样更改 IPv4 地址 我已经检查了以下链接 但没有找到足够的帮助 所以我发布了这个问
  • 从 DataRow 单元格解析 int [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 如何从 DataRow 单元格解析 int 值 Int32 Parse item QuestionId ToString 这段代码可以工作 但看
  • Type.GetInterfaces() 仅适用于声明的接口

    首先 像这样的问题有很多 也许有些OP甚至在问同样的问题 问题是这些问题的答案 无论是否接受 都没有真正回答这个问题 至少我找不到 如何确定类直接声明的接口 而不是由父级或声明的接口继承的接口 e g interface I interfa
  • 如何同步nosql db(ravendb)中的更改

    我已经开始在 RavenDB 的示例上学习 NoSQL 我从一个最简单的模型开始 假设我们有由用户创建的主题 public class Topic public string Id get protected set public stri
  • 如何从 Access 数据库中读取“是/否”值作为布尔值?

    帮我找回YES NO来自 MS Access 的布尔格式数据类型 我尝试解析它 但它总是返回 false 更新 实际上不是问题抱歉 它确实接受 YES NO 作为布尔值 OleDbconnection dbConnect new OleDb
  • “1个未解决的外部”C++

    我已经检查了所有文件之间的连接以及类和函数定义 但每次我尝试运行我的程序时 它都会阻止我并告诉我它有 1 个未解析的外部 该程序应该打开多个文件 一个 学生 文件和一个 成绩 文件 从中读取数据 然后使用 查询文件 来查找数据 找到查询中要
  • Xcode 7 调试器不会中断内联标头函数

    过去五年我一直在各种 C 项目中使用 Xcode 没有出现这个问题 今天 我打开了一个较旧的项目 大约 2 年前 并尝试通过在该函数中放置一个活动断点来调试头文件中的内联函数 由于某种原因 调试器不会中断此代码 但是 如果我在调用该函数的
  • 卸载程序

    我正在尝试使用此代码卸载程序 但它似乎不起作用 我尝试过其他答案 但似乎也不起作用 有人可以帮助我吗 我正在尝试按给定名称 displayName 卸载该程序 例如 我给出 displayName Appname 那么此代码应该从我的计算机
  • 在windows + opengl中选择图形设备

    我知道如何使用 openGL 打开窗口 使用 Win32 或其他工具包 但是当系统有2块显卡时 如何选择要渲染的图形设备 我的编程语言是 C 我专注于 Windows 但任何示例都将受到欢迎 编辑 也许更好地解释我的问题是个好主意 以便添加
  • 实体框架代码首次日期字段创建

    我正在使用实体框架代码优先方法来创建我的数据库表 下面的代码 创建一个DATETIME数据库中的列 但我想创建一个DATE柱子 DataType DataType Date DisplayFormatAttribute ApplyForma
  • 如何使用 C# 为 azure devops 变量赋值

    我有 selenium C 测试脚本 可以从浏览器获取令牌 我有两个 azure devops 任务 一个用于执行 selenium 测试 另一个用于执行 API 测试 我想将 selenium 测试获取的令牌传递给 API 测试执行任务

随机推荐