p1和p2是指向int的指针,如果p2>p1有效,那么p2-p1有效吗?

dou*_*oug 3 c++ pointers pointer-arithmetic language-lawyer

可以比较指向类成员变量的指针,结果取决于声明顺序。请参阅规范例如,编译器资源管理器中的此示例有效并返回 true (1):

struct A {
    int a0 = 1;
    int a1 = 2;
};

consteval int foo()
{
    A a;
    int* p1 = &a.a0;
    int* p2 = &a.a1;
    return p2 > p1;
}

int main()
{
    return foo();
}
Run Code Online (Sandbox Code Playgroud)

因此,人们会期望它p2-p1会返回指针之间的距离(以 int 对象为单位)。它在运行时执行。编译器浏览器

struct A {
    int a0 = 1;
    int a1 = 2;
};

int foo()
{
    A a;
    int* p1 = &a.a0;
    int* p2 = &a.a1;
    return p2 - p1;
}

int main()
{
    return foo();
}
Run Code Online (Sandbox Code Playgroud)

但不是在编译时。GCC、CLANG 和 MSVC 的行为都不同。GCC 编译并返回预期值,CLANG 抱怨 UB,MSVC 编译但返回 4,而不是 1,以字节为单位的距离!编译器资源管理器

CLANG:注意:相减的指针不是同一数组的元素

哪个是对的?

Rya*_*ing 14

您不能减去指向对象的指针,除非它们是同一数组的元素。这是未定义的行为,因此您可以获得不同的结果。

\n
\n

如果 P 和 Q 分别指向同一数组对象 x 的数组元素 i 和 j,则表达式 P - Q 的值为 i \xe2\x88\x92 j。

\n

否则,行为是未定义的。

\n
\n

http://eel.is/c++draft/expr.add#5.2

\n

clang 将其标记为未定义行为是正确的,gcc 和 msvc 做任何他们想做的事情是正确的,因为它是未定义的行为。如果该函数consteval只有 clang 是正确的,其他函数应该发出诊断

\n

  • 从技术上讲,如果行为未定义,所有编译器都是正确的,因为标准没有强加任何要求,并且根本不需要诊断未定义的行为。可能更公平地说,clang 提供了一种诊断,以人类更容易理解的方式识别实际问题,即编译器之间的差异在于实现的质量,而不是正确性。 (4认同)