【问题标题】:In C++, What does "access" mean in the strict aliasing rule?在 C++ 中,“访问”在严格的别名规则中是什么意思?
【发布时间】:2015-03-12 03:20:36
【问题描述】:

3.10/10 说:

如果程序尝试通过以下类型之一以外的左值来访问对象的存储值,则行为未定义:

但是,“访问”一词在任何地方都没有定义。在这种情况下,它是指读取,还是读取或修改


在 C 标准中,它被明确定义为读取或修改。但是在 C++11 中,它似乎在不同的时间有不同的含义,例如:

1.9/8:

对易失性对象的访问严格按照抽象机的规则进行评估。

显然这是为了读取或修改,但是在许多其他地方,例如 1.10/24:

  • 访问或修改易失性对象,或

它的使用好像它只是意味着读取

【问题讨论】:

  • 您可以将标题缩短为:“在 C++ 中,‘访问’是什么意思?”这是一个很好的问题。 (当然,对于严格的别名规则,其意图肯定是“读取或修改”,类似于C。)
  • @Nemo 同意,尽管我对这个特殊案例最感兴趣。这可能是一个单独的问题。
  • 好吧,不管他们在本节中的意图如何,他们肯定没有说清楚,所以我想说你肯定在规范中发现了一个错误。
  • 标准在这类事情上是出了名的糟糕。即使是像我这样狂热的语言律师也会避免像瘟疫这样的问题。你靠自己;)
  • @LightnessRacesinOrbit 呵呵。严格的混叠问题非常可怕,可以在没有这种模糊性的情况下解开。我一直认为它应该和 C 中的一样;但我一直在阅读有关严格别名的其他一些答案(特别是与结合新位置有关),它们都默认依赖 access 仅表示 read,所以我是希望在进一步评论/发布严格别名之前清除这个问题

标签: c++ language-lawyer strict-aliasing


【解决方案1】:

它必须意味着读和写,否则规则意义不大。考虑http://blog.llvm.org/2011/05/what-every-c-programmer-should-know.html的例子:

float *P;
void zero_array() {
   int i;
   for (i = 0; i < 10000; ++i)
       P[i] = 0.0f;
}

只有当编译器可以假定没有一个P[i] 别名P 时,上面的示例代码才能优化为memset。但是考虑一个只有 reading 从不允许的 glvalue 是 UB 的世界,那么即使 P[i] 为某些 i 别名 P,上面的代码也不会调用 UB - 例如,如果有人这样做了P = (float *) &amp;P;,因为P 的所有读取 都是完全合法的——它们都使用左值表达式P


编辑CWG issue 1531 是正确的。该问题已于 2013 年 4 月转为 DR(缺陷报告)状态,但无论出于何种原因,该解决方案并未应用于工作文件。

【讨论】:

  • 很好的例子(就像你在其他评论中的例子)
  • 我认为标准指定 PODS 的跨类型读取产生潜在的不确定值,并且 PODS 的跨类型写入将其设置为潜在的中间值,我认为没有困难,至少如果标准更清楚地说明了在使用没有自然陷阱表示的类型的中间值时会发生什么和不能发生什么(无论如何,标准都应该解决这一点,恕我直言)。
【解决方案2】:

我不声称自己是语言律师。不过……

我会将短语“访问对象的存储值”解释为“读取对象的存储值”。

鉴于上一段谈到修改对象,这种解释更有意义。

9 如果一个表达式可用于修改它所引用的对象,则该表达式称为可修改的。试图通过不可修改的左值或右值表达式修改对象的程序是格式错误的。

【讨论】:

  • 通过这个阅读,像int a = 0; *((short *) &amp;a) = 100; std::cout &lt;&lt; a; 这样的东西不会破坏严格的别名。这没什么意义。
  • @T.C.我明白你的意思了。标准中是否有 readwrite 更严格的地方?
猜你喜欢
  • 2015-05-31
  • 2011-02-15
  • 2016-02-24
  • 2019-01-29
  • 2013-03-11
  • 2015-10-15
  • 1970-01-01
  • 2017-02-25
  • 2015-05-09
相关资源
最近更新 更多