How to Compare Pointers

How to compare pointers?

Yes, that is the definition of raw pointer equality: they both point to the same location (or are pointer aliases); usually in the virtual address space of the process running your application coded in C++ and managed by some operating system (but C++ can also be used for programming embedded devices with micro-controllers having a Harward architecture: on such microcontrollers some pointer casts are forbidden and makes no sense - since read only data could sit in code ROM)

For C++, read a good C++ programming book, see this C++ reference website, read the documentation of your C++ compiler (perhaps GCC or Clang) and consider coding with smart pointers. Maybe read also some draft C++ standard, like n4713 or buy the official standard from your ISO representative.

The concepts and terminology of garbage collection are also relevant when managing pointers and memory zones obtained by dynamic allocation (e.g. ::operator new), so read perhaps the GC handbook.

For pointers on Linux machines, see also this.

How does pointer comparison work in C? Is it ok to compare pointers that don't point to the same array?

According to the C11 standard, the relational operators <, <=, >, and >= may only be used on pointers to elements of the same array or struct object. This is spelled out in section 6.5.8p5:

When two pointers are compared, the result depends on the
relative locations in the address space of the objects pointed to.
If two pointers to object types both point to the same object, or
both point one past the last element of the same array
object, they compare equal. 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. If the expression P points to an element of an array
object and the expression Q points to the last element of the
same array object, the pointer expression Q+1 compares greater than P.
In all other cases, the behavior is undefined.

Note that any comparisons that do not satisfy this requirement invoke undefined behavior, meaning (among other things) that you can't depend on the results to be repeatable.

In your particular case, for both the comparison between the addresses of two local variables and between the address of a local and a dynamic address, the operation appeared to "work", however the result could change by making a seemingly unrelated change to your code or even compiling the same code with different optimization settings. With undefined behavior, just because the code could crash or generate an error doesn't mean it will.

As an example, an x86 processor running in 8086 real mode has a segmented memory model using a 16-bit segment and a 16-bit offset to build a 20-bit address. So in this case an address doesn't convert exactly to an integer.

The equality operators == and != however do not have this restriction. They can be used between any two pointers to compatible types or NULL pointers. So using == or != in both of your examples would produce valid C code.

However, even with == and != you could get some unexpected yet still well-defined results. See Can an equality comparison of unrelated pointers evaluate to true? for more details on this.

Regarding the exam question given by your professor, it makes a number of flawed assumptions:

  • A flat memory model exists where there is a 1-to-1 correspondence between an address and an integer value.
  • That the converted pointer values fit inside an integer type.
  • That the implementation simply treats pointers as integers when performing comparisons without exploiting the freedom given by undefined behavior.
  • That a stack is used and that local variables are stored there.
  • That a heap is used to pull allocated memory from.
  • That the stack (and therefore local variables) appears at a higher address than the heap (and therefore allocated objects).
  • That string constants appear at a lower address then the heap.

If you were to run this code on an architecture and/or with a compiler that does not satisfy these assumptions then you could get very different results.

Also, both examples also exhibit undefined behavior when they call strcpy, since the right operand (in some cases) points to a single character and not a null terminated string, resulting in the function reading past the bounds of the given variable.

Compare pointer with reference

std::addressof(*ptr) seems redundant. If you have a pointer to the object, and you need a pointer to the object, then why indirect through the pointer and then get the pointer to object that was being pointed at? ptr == std::addressof(y) should work just as fine. As long as you want to compare equality of the address...

(To check whether both objects are equal)

Comparing equality of addresses is comparing identity, i.e. whether they are the same object. To compare equality of objects, you'd generally compare their value. For example, following variables are not the same object and thus do not have the same address, but they are equal in value (assuming sane copy constructor):

MemberData x;
MemberData y = x;

How to compare two pointers?

When you compare pointers you are actually comparing the values pointed by those. This is because there are a lot of implementations in std of the type:

impl<'_, '_, A, B> PartialEq<&'_ B> for &'_ A
where
A: PartialEq<B> + ?Sized,
B: ?Sized,

that do exactly that.

If you want to compare the pointers themselves you can use std::ptr::eq:

pub fn eq<T: ?Sized>(a: *const T, b: *const T) -> bool

Note that even though it takes raw pointers, it is safe because it does not dereference the pointers. Since there is an automatic coercion from a reference to a raw pointer, you can use:

if std::ptr::eq(item, test.last().unwrap()) {
println!("Last item!");
}

Three-way comparison of pointer to functions fails

The result of using normal relational operators on function pointers is unspecified if the pointers are unequal. You can compare pointers to objects (but only meaningfully if they're pointers into the same array or structure), but relating function pointers isn't really viable.

Rather than taking the sometimes-unspecified route, C++20 simply forbids using <=> for non-object pointers.

You can test for equality between such pointers, but not their relative ordering. If you absolutely need to do this for some reason, you can cast the pointers to void*s and use std::less<> for such comparisons.



Related Topics



Leave a reply



Submit