在C++中,指针比较是未定义行为还是不确定行为?

8
《C++程序设计语言》第三版(Stroustrup)指出,指针的减法只有在两个指针都指向同一数组元素时才定义(虽然语言没有快速确保这一点的方法)。当从一个指针中减去另一个指针时,结果是两个指针之间的数组元素数量(一个整数)。可以将整数添加到指针或从指针中减去整数;在这两种情况下,结果都是一个指针值。如果该值不指向与原始指针相同的数组元素或超出其范围,则使用该值的结果是未定义的。
例如:
void f ()
{
    int v1 [10];
    int v2 [10];
    int i1 = &v1[5] - &v1[3];   // i1 = 2
    int i2 = &v1[5] - &v2[3];   // result undefined
}

我是一名有用的助手,可以进行文本翻译。
我正在阅读维基百科上关于未指定行为的内容。它说:
在C和C++中,仅当指针指向同一对象的成员或同一数组的元素时,指针之间的比较才是严格定义的。
例如:
int main(void)
{
  int a = 0;
  int b = 0;
  return &a < &b; /* unspecified behavior in C++, undefined in C */
}

所以,我很困惑。哪个是正确的?维基百科还是Stroustrup的书?C++标准对此有何规定?

如果我有误解,请纠正我。


1
我没有看到这两个摘录之间的冲突。你能澄清一下你的困惑吗? - Amit
3
Stroustrup提到指针减法(也称为指针差分),该示例展示的是差值计算。你引用自维基百科的文章涉及逻辑指针比较。 - WhozCraig
1个回答

13
请注意,指针相减和指针比较是不同的操作,具有不同的规则。
根据C++14标准5.6/6,对于指针相减: 除非两个指针都指向同一数组对象的元素或者一个数组对象的最后一个元素之后,否则行为是未定义的。
根据C++14标准5.9/3-4,关于指针比较: 1. 如果两个指针分别指向同一数组的不同元素或其子对象,则下标较高的元素对应的指针比较大。 2. 如果一个指针指向数组的一个元素或其子对象,而另一个指针指向该数组的最后一个元素之后,那么后一个指针比较大。 3. 如果两个指针分别指向同一对象的不同非静态数据成员或其子对象(递归地),且这两个成员具有相同的访问控制,并且它们所在的类不是一个union,则后声明的成员对应的指针比较大。
如果两个操作数p和q相等(5.10),则`p<=q`和`p>=q`都返回true,`pq`都返回false。否则,如果一个指针p比另一个指针q大,则`p>=q`、`p>q`、`q<=p`和`q=p`和`q>p`都返回false。否则,每个运算符的结果是未指定的。

1
在最后一句话中,“否则,每个运算符的结果是未指定的。”为什么应该是未指定而不是未定义?这是因为标准定义了可能的结果只有True或False,因此不会发生其他行为吗? - Lorenzo Belli
1
@LorenzoBelli,“未定义”比“未指定”错误更严重,可能会导致程序崩溃等任何情况。对于未指定行为,唯一的问题是你不知道结果是true还是false - 编译器可以比标准要求更严格地指定该行为。通常规范编写者想要允许良好行为的程序,并且仅在绝对必要时指定未定义行为。 - Mark Ransom
@LorenzoBelli 此外,如果在未指定行为的情况下进行两次比较,则运算符必须返回相同的值。但是对于 UB,每个比较都可以独立地返回 true/false。 - Ajay Brahmakshatriya
1
@AjayBrahmakshatriya:没有要求产生未指定结果的操作必须始终如一地这样做。如果pq标识不相关的对象,则给定int a=p>q,b=p>q,c=a;,编译器可以使ab成为值0和1的任何组合。然而,编译器需要使ca相等。 - supercat

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