“不是必需的”== 未定义的行为?

for*_*818 32 c++ pointers undefined-behavior comparison-operators language-lawyer

我的问题主要是关于术语以及如何解释标准。

[expr.rel]#4 :

比较指向对象的不等指针的结果是根据符合以下规则的偏序定义的:

(4.1) 如果两个指针指向同一个数组的不同元素,或者指向其子对象,则要求指向下标较高的元素的指针比较大。

(4.2) 如果两个指针递归地指向同一对象的不同非静态数据成员,或指向此类成员的子对象,则要求后面声明的成员的指针比较大,前提是这两个成员具有相同的访问控制( [class.access]),两个成员都不是零大小的子对象,它们的类也不是联合。

(4.3) 否则,两个指针都不需要比较大于另一个。

我对如何解释(4.3)有点困惑。这是否意味着这

#include <iostream>
int main() {
    int x;
    int y;
    std::cout << (&x < &y);
    std::cout << (&x < &y);
}
Run Code Online (Sandbox Code Playgroud)

是...

  • 有效的 C++ 代码,输出为1100
  • 无效代码,因为它具有未定义的行为

?

换句话说,我知道(4.3)确实适用于此,但我不确定其含义。当标准说“它可以是 A 或 B”时,这与说“它是未定义的”相同吗?

Kei*_*son 25

在 C++ 标准的各个版本中以及问题中引用的最近草案中,措辞都发生了变化。(有关血腥细节,请参阅我对该问题的评论。)

C++11 说:

其他指针比较未指定。

C++17 说:

否则,两个指针的比较都不大于另一个。

问题中引用的最新草案说:

否则,两个指针都不需要比较大于另一个。

这一变化是为了回应一个问题,即““比较大”一词不必要地令人困惑”。

如果您查看标准草案中的周围上下文,很明显,在其余情况下,结果是unspecified。引自 [expr.rel](斜体字是我的总结):

比较指向对象的不等指针的结果是根据符合以下规则的偏序定义的:

  • [指向同一数组元素的指针]

  • [指向同一对象成员的指针]

  • [剩余情况]否则,两个指针都不需要比较大于另一个。

如果两个操作数pq比较相等,p<=q并且 p>=q这两个产量truep<qp>q两个产量 false。否则,如果指针p比较不是一个指针更大的和所有的产量和,,,和 所有的产量。否则,每个运算符的结果都是未指定的。q, p>=q, p>q, q<=p,q<ptruep<=qp<qq>=pq>pfalse

所以<在这种情况下运算符的结果是未指定的,但它没有未定义的行为。它可以是对的,也可以是错的,但我认为不需要保持一致。该程序的输出可以是任意的000110,或11


cig*_*ien 7

对于提供的代码,这种情况适用:

(4.3) 否则,两个指针都不需要比较大于另一个。

没有提到 UB,因此严格阅读“两者都不需要”表明每次评估的比较结果可能会有所不同。

这意味着程序可以有效地输出以下任何结果:

00
01
10
11
Run Code Online (Sandbox Code Playgroud)

  • 不过,您很难找到一个能够生成 01 和 10 情况的编译器。 (3认同)
  • (DS9K = DeathStation 9000,一台假设的计算机,当涉及到未定义的行为时,它尽可能没有帮助。在 DS9K 上,未定义的行为会发射死亡射线或导致全球变暖或使恶魔从用户的鼻子中飞出。) (3认同)
  • @Jeffrey DS9K 捆绑的编译器可能会这样做。 (2认同)