究竟什么是“假设”规则?

What exactly is the "as-if" rule?

提问人:Alok Save 提问时间:3/30/2013 最后编辑:Remy LebeauAlok Save 更新时间:2/12/2021 访问量:12899

问:

正如标题所说:

究竟什么是“假设”规则?

一个典型的答案是:

允许不更改程序的可观察行为的任何和所有代码转换的规则

有时,我们会不断从某些实现中获得行为,这些行为归因于此规则。很多次都错了。

那么,这条规则到底是什么呢?该标准没有明确提及该规则作为章节或段落,那么该规则究竟属于该规则的范畴范围是什么?

对我来说,这似乎是一个灰色地带,标准没有详细定义。有人可以引用标准中的参考资料详细说明细节吗?

注意:将其标记为 C 和 C++,因为它与这两种语言相关。

C C 优化 C++-FAQ AS-IF

评论

2赞 Alexey Frunze 3/30/2013
它指的是抽象机器。
0赞 curiousguy 5/28/2019
"将其标记为 C 和 C++,因为它与两种语言相关“它在任何语言中都相关。
0赞 curiousguy 5/28/2019
@AlexeyFrunze “它指的是抽象机器”的状态,它指的是“抽象机器”的状态,它是一个工具而不是目的,并且在符合方面无关紧要,因为它是“抽象”,即一个不真实的规范工具。

答:

120赞 Andy Prowl 3/30/2013 #1

什么是“假设”规则?

假设”规则基本上定义了允许实现在合法的 C++ 程序上执行哪些转换。简而言之,所有不影响程序的“可观察行为”的转换(有关精确定义,请参见下文)都是允许的。

目标是让实现可以自由地执行优化,只要程序的行为符合抽象机器的 C++ 标准指定的语义。


该标准在哪里引入了此规则?

C++11 标准在第 1.9/1 段中引入了“假设”规则:

本国际标准中的语义描述定义了一个参数化的非确定性抽象 机器。本国际标准对符合要求的实施结构没有要求。 特别是,它们不需要复制或模仿抽象机器的结构。相反,顺从是 实现需要模拟(仅)抽象机器的可观察行为,如所述 下面。

此外,解释性脚注还添加了:

这一规定有时被称为“假设”规则,因为实现可以自由地无视任何要求 国际标准,只要结果是好像已经遵守了要求,只要可以从中确定 程序的可观察行为。例如,如果可以的话,实际实现不需要计算表达式的一部分 推断其值未被使用,并且不会产生影响程序可观察行为的副作用。


该规则究竟要求什么?

第1.9/5段进一步规定:

执行格式良好的程序的符合要求的实现应产生相同的可观察行为 作为具有相同程序的抽象机器的相应实例的可能执行之一 和相同的输入。但是,如果任何此类执行包含未定义的操作,则此国际 标准对使用该输入执行该程序的实现没有要求(甚至没有 关于第一个未定义操作之前的操作)。

值得强调的是,此约束仅适用于“执行格式良好的程序”,并且执行包含未定义行为的程序的可能结果是不受约束的。第1.9/4段也明确指出了这一点:

某些其他操作在本国际标准中被描述为未定义(例如,效果 尝试修改 const 对象)。[ 注:本国际标准对 包含未定义行为的程序的行为。——尾注]

最后,关于“可观察行为”的定义,第1.9/8段如下:

对符合要求的实现的最低要求是:

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

— 在程序终止时,写入文件的所有数据应与以下可能的结果之一相同: 根据抽象语义执行程序会产生。

— 交互式设备的输入和输出动态应以提示 输出实际上是在程序等待输入之前传递的。什么是交互式设备 是实现定义的。

这些统称为程序的可观察行为。[ :更严格 抽象语义和实际语义之间的对应关系可以由每个实现定义。—完 注意 ]


在哪些情况下,此规则不适用?

据我所知,“假设”规则的唯一例外是复制/移动省略,即使类的复制构造函数、移动构造函数或析构函数有副作用,也是允许的。第12.8/31段规定了具体条件:

当满足某些条件时,允许实现省略类的复制/移动构造 对象,即使为复制/移动操作选择的构造函数和/或为对象选择的析构函数也是如此 有副作用。[...]

评论

2赞 Alok Save 3/30/2013
我看过这个引文。目前尚不清楚的是可观察行为的定义。究竟什么才算是可观察的行为?复制省略是假如规则的例外,这是众所周知的,并不是我问题的一部分。
2赞 Oliver Charlesworth 3/30/2013
@AlokSave:在 C 标准中,我们看到“访问易失性对象、修改对象、修改文件或调用执行任何这些操作的函数都是副作用”。大概在 C++ 标准中有一些等效的东西。非正式地,我猜是“任何改变与外界互动的东西”。
1赞 Mats Petersson 3/30/2013
任何改变抽象机器状态的行为(因此,改变传入的变量或全局变量,或读取和写入 I/O 设备的行为)。
1赞 harold 3/30/2013
这是否意味着只要之后没有发生任何可观察的事情,就允许删除一个不执行任何操作的无限循环?
7赞 vonbrand 3/30/2013
需要特别注意的一点是,它仅适用于法律程序。任何调用未定义行为的行为都明确超出了任何范围。
17赞 Antti Haapala -- Слава Україні 9/28/2017 #2

在 C11 中,从不使用该名称调用规则。然而,C就像C++一样,用抽象机器来定义行为。as-if 规则位于 C11 5.1.2.3p4 和 p6 中:

  1. 在抽象机器中,所有表达式都按照语义指定进行计算。如果实际实现可以推断出表达式的值未被使用,并且不会产生所需的副作用(包括由调用函数或访问可变对象引起的任何副作用),则无需计算表达式的一部分。

  2. [...]

  3. 对符合要求的实现的最低要求是:

    • 对对象的访问严格按照抽象机器的规则进行评估。volatile
    • 在程序终止时,写入文件的所有数据应与根据抽象语义执行程序所产生的结果相同。
    • 交互设备的输入和输出动态应采取 地点,如 7.21.3 中指定。这些要求的目的是尽快出现无缓冲或行缓冲的输出,以确保提示消息在程序等待输入之前实际出现。

     

    这是程序的可观察行为。

-1赞 curiousguy 5/28/2019 #3

在 C、C++、Ada、Java、SML 中...在任何通过描述程序(通常许多可能的、非确定性的)行为(暴露于 I/O 端口上的一系列交互)来明确指定的编程语言中,没有明确的 as-if 规则

不同规则的一个例子是,除以零会引发异常(Ada、Caml)或空取消引用会引发异常(Java)。您可以更改规则以指定其他内容,最终会得到一种不同的语言(有些人宁愿称之为“方言”(*)。一个不同的规则可以指定编程语言的一些不同用法,就像不同的语法规则涵盖一些语法结构一样。

(*)根据一些语言学家的说法,方言是一种带有“军队”的语言。在这种情况下,这可能意味着一种没有委员会的编程语言和特定的编译器编辑器行业。

仿佛规则不是一个单独的规则;它没有特别涵盖任何程序,甚至不是一个可以以任何方式讨论、删除或更改的规则:所谓的“规则”只是重申程序语义是定义的,并且只能根据程序执行与“外部”世界的可见交互进行可移植(普遍)定义。

外部世界可以是 I/O 接口 (stdio)、GUI,甚至是输出纯应用语言结果值的交互式解释器。在 C 和 C++ 中,包括对易失性对象的(模糊指定的)访问,这是另一种说法,即给定点的某些对象必须严格按照 ABI(应用程序二进制接口)在内存中表示,而无需显式提及 ABI。

什么是执行跟踪的定义,也称为可见或可观察行为,定义了“假设规则”的含义。as-if 规则试图解释它,但这样做,它让人们感到困惑多于澄清事情,因为它表达了作为附加语义规则的表达,为实现提供了更多的回旋余地。

总结:

  • 所谓的“假设规则”并没有放松对实现的任何限制。
  • 您不能删除任何编程语言中根据可见行为(为与外部世界交互而编写的执行跟踪)指定的 as-if 规则来获取不同的方言。
  • 不能将 as-if 规则添加到任何未在可见行为方面指定的编程语言。

评论

1赞 curiousguy 2/22/2020
如果人们认为我错了,并且有一个明显的“好像规则”,他们为什么不尝试描述没有“规则”的C++(一种方言)的变体呢?没有 C++ 规范意味着什么?绝对不可能判断编译器是否符合要求。甚至定义一致性。
0赞 supercat 7/7/2021
“假设”规则意味着,在潜在有用的优化可能影响程序行为的任何情况下,要么需要禁止优化,要么需要将导致这种情况的任何操作组合描述为UB。
0赞 Andrew Henle 1/14/2022
没有明确的 as-if 规则嗯,错了。“假设规则”甚至在 C11 标准的索引中作为 - 等待它 - “假设规则”