C++的as-if规则允许存储重新排序吗?

4
"as-if"规则基本上定义了一个实现可以对合法的C++程序进行哪些转换。简而言之,所有不影响程序可观察行为的转换都是允许的。
至于“可观察行为”到底是什么意思,cppreference.com似乎与标准中给出的关于输入/输出的定义有所不同。我不确定那是否是标准的重新解释,或者是错误。
cppreference.com的"as-if"规则:
  • 所有输入和输出操作按照原程序编写的顺序和内容发生。
标准的"as-if"规则:
  • 交互设备的输入和输出动态应以这样的方式进行,即在程序等待输入之前实际传递提示输出。什么构成交互式设备是由实现定义的。
这个差异对我很重要,因为我想知道普通店的重新排序是否是有效的编译器优化。根据cppreference的措辞,内存存储应属于其提到的“输出操作”。但根据标准,内存存储似乎不是“交互设备的输出动态”(反正交互设备是什么?)。
以下是一个示例。
int A = 0;
int B = 0;

void foo()
{
    A = B + 1;              // (1)
    B = 1;                  // (2)
}

现代编译器可能会生成以下代码,用于函数foo

mov     0x804a018, %eax
movl    $0x1, 0x804a018    ; store 1 to B
add     $0x1, %eax         
mov     %eax, 0x804a01c    ; store 1 to A
ret

正如所见,将店铺 A 的重新排序与店铺 B 相匹配。这是否符合“似乎”规则?这种重新排序是否符合标准?

"(交互设备是什么?) ”这就是“提示输出实际上在程序等待输入之前已经传递”的事情。控制台。" - curiousguy
2个回答

3
真正的“as-if”规则表述在标准的§1.9/8中:
  • 对于易失性对象的访问严格按照抽象机的规则进行评估。
  • 在程序终止时,写入文件的所有数据都必须与根据抽象语义执行程序产生的可能结果之一相同。
  • 交互设备的输入和输出动态应以这样的方式进行,即在程序等待输入之前实际提供提示输出。什么构成交互设备是由实现定义的。
由于AB不是易失性的,因此可以进行重新排序。

3
如果cppreference.com与C++标准的实际文本不一致,那么cppreference.com是错误的。唯一能够超越标准文本的是更新版本的标准和缺陷报告的官方决议(有时会被整合到称为“技术勘误”的文档中,这是标准的小版本更新的花哨名称)。
然而,在这种情况下,您误解了cppreference.com所指的“输入和输出操作”。 (如果记忆无误,该文本是从旧版本的标准中逐字引用的。)存储到内存的操作不是输出操作。仅写入文件(即任何stdio.hiostream输出流或其他实现定义机制,例如Unix文件描述符)才算作此规则的输出。

在2011年修订之前,C和C++标准假定了一个单线程的抽象机器,因此没有关于存储顺序的规定,因为没有办法观察到程序顺序之外的存储。 C(++)11作为新的多线程规范的一部分增加了大量存储顺序规则。


1
如果将 y 发送到输出设备(例如使用 std::cout << y;),那么 as-if 规则可能会将该代码转换为等效的 std::cout << 4; - Cubbi
@Cubbi 在我的原始情况下,它并没有写入任何输出流。它只是将两个值存储到同一个内存位置,这并没有被列为任何可观察行为,对吧? - Eric Z
2
@EricZ int main(void) { int x, y; x = 3; x = 4; y = x; printf("%d %d\n", x, y); return 0; } 必须打印出 4 4 并成功退出。所谓的“as-if”规则意味着编译器可以发出任何机器指令序列,只要它们具有这些效果,不多也不少。特别是,交换对 x 的两个存储将导致程序打印 3 3,因此是错误的。 - zwol
2
@EricZ 然而,int main(void) { int x, y; x = 3; x = 4; y = x; return 0; } 没有任何依赖于 xy 的可观察效果,因此编译器可以自由地对它们进行任何操作:特别是它可以自由地不为除了 return 0; 以外的任何代码生成机器码,只要你打开优化选项,大多数现代编译器都会这样做。 - zwol
@Zack。那很有道理。我好奇的是,在一个大型项目中,编译器如何知道改变两个存储的顺序是否会改变程序中非常晚的未来观察行为 - Eric Z
显示剩余14条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接