What does it mean to compare pointers using relational operators?
Asked Answered
R

1

8

If I have two pointer variables, a and b, what does it mean to to use the statement "a < b"? Is doing so supposed to compare the values of their memory addresses? If so, what would be the order of memory addresses in the computer?

Rayshell answered 10/11, 2017 at 18:50 Comment(3)
I suspect that something like this will be very language specific. In some naive cases pointers are literally (or can be treated like) memory location. In other cases they are a very specific type, and operators will have type specific behaviour.Dimitri
Related Given that p is a pointer is “p > nullptr” well-formed?Meenen
My answer to Rationale for pointer comparisons outside an array to be UB is also related.Meenen
G
7

In C and C++, comparing pointers using relational operators is allowed in the case where you have two pointers into the same array and want to see their relative ordering (there's an exception to this rule that I'll mention in a little bit). For example, imagine that p and q each point somewhere into the middle of array arr, as shown here:

            int arr[9];
            int* p = &arr[1];
            int* q = &arr[4];

    +-----+-----+-----+-----+-----+-----+-----+-----+-----+
arr |     |     |     |     |     |     |     |     |     |
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+
             ^                 ^
             |                 |
             p                 q

In this case, the expression p < q asks "is the index in the array that p points at lower than the index in the array that q points at?" In the above context, the answer is "yes." If p and q were reversed, or if they pointed at the exact same element, the answer would be "no."

The language standards in C and C++ both say that the result of comparing pointers that don't point into the same array is unspecified, which intuitively makes sense because unrelated objects might be scattered around pretty much randomly in memory, or be related in a way that's implementation-dependent (does your stack grow up or down?)

The one exception to this is that you're allowed to compare a pointer one object past the end of an array to a pointer in the array. For example, take a look at this setup:

            int arr[9];
            int* p = &arr[1];
            int* q = &arr[9];

    +-----+-----+-----+-----+-----+-----+-----+-----+-----+
arr |     |     |     |     |     |     |     |     |     |
    +-----+-----+-----+-----+-----+-----+-----+-----+-----+
             ^                                              ^
             |                                              |
             p                                              q

Here, q doesn't point into the array arr. However, the language spec allows you to safely compare p and q. This is why, for example, you can safely use this iterator-style loop in C++:

for (int* itr = arr; itr != arr + /* arr's size */; itr++) {
    ...
}
Gadid answered 10/11, 2017 at 19:28 Comment(5)
To add: "... in the case where you have two pointers into the same array or object". This array discussion also applies to a single object as if it was an array of one. some_type x; &x+1 > &x is well defined. §6.5.8 4Straiten
You can also compare pointers to members of the same aggregate object, e.g., a pointer to the int a in a struct object with a pointer to the double b in the same object.Drapery
@EricPostpischil I didn't know you could do that. I assume you need to use some flavor of char * pointers across objects of different types to avoid strict aliasing violations?Gadid
@templatetypedef: I was wrong about being able to compare disparate members of an object. You can compare members of an object, but they must have compatible types. Then the standard says “If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal.”Drapery
@templatetypedef: I cannot say I have ever seen it used. It’s a bit weird; you would have to have two pointers that you know point into the same struct, but you do not know where in the struct they point. Did you forget? Why do you even care? I suppose there is a case where you have some link structure where sometimes you point to one member of the struct (e.g., a “forward” link in a chain) and sometimes you point to another (e.g., a “reverse” link), and comparing would let you figure out which of those a particular pointer points to.Drapery

© 2022 - 2024 — McMap. All rights reserved.