c++pointerslanguage-lawyerpointer-arithmetic

p1 and p2 are pointers to ints, if p2>p1 is valid, is p2-p1 valid?


Pointers to class member variables can be compared and the results depend on the declaration sequence. See this in the spec For instance this example in compiler explorer is valid and returns 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();
}

So one would expect that p2-p1 would return the distance, in int objects, between the pointers. And it does at runtime. compiler explorer

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();
}

But not at compile time. GCC, CLANG, and MSVC all behave differently. GCC compiles and returns the expected value, CLANG complains UB, and MSVC compiles but returns 4, not 1, the distance in bytes! Compiler Explorer

CLANG: note: subtracted pointers are not elements of the same array

Which is correct?


Solution

  • You may not subtract pointers to objects unless they are elements of the same array. It is undefined behavior so you can get different results.

    if P and Q point to, respectively, array elements i and j of the same array object x, the expression P - Q has the value i − j.

    Otherwise, the behavior is undefined.

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

    clang is correct in labeling it as undefined behavior, gcc and msvc are correct in doing whatever they want because it is undefined behavior. If the function is consteval then only clang is correct, the others should emit a diagnostic