Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Undefined Behavior when subtracting pointers

Tags:

c++

The C++ standard says that subtracting pointers from non-array elements is UB:

int a, b;
&a - &b; // UB, since pointers don't point to the same array.

But if both pointers are casted to uintptr_t, then both exressions are no longer pointer expressions and subtracting them seems to be legal from the Standard's perspective:

int a, b;
reinterpret_cast<uintptr_t>(&a) - reinterpret_cast<uintptr_t>(&b); 

Is this correct or am I missing something?

like image 541
Bikineev Avatar asked Oct 15 '22 05:10

Bikineev


2 Answers

The subtraction of the integers is legal in the sense that behaviour is not undefined.

But the standard doesn't technically have guarantees about the values of the converted integers, and consequently you have no guarantees about the value of result of the subtraction either (except in relation to the unspecified integer values) - you could get a large value or a small value (or if the pointers had non-interconvertible types, then subtraction of converted intergers of different objects could even yield zero) depending on the system.

Furthermore, if you did some other pointer arithmetic that would result in a pointer value i.e. convert pointer to integer and add offset, then there is technically no guarantee that that converting the result of the addition back to a pointer type would yield the pointer value at that offset from the original. But it would probably work (assuming there actually exists an object of correct type at that address) except perhaps on systems using segmented memory or something more exotic.

like image 71
eerorika Avatar answered Nov 12 '22 21:11

eerorika


You are correct.

The behaviour on subtracting pointers that do not point to elements of the same array is undefined. For this purpose a pointer is allowed to be one beyond the final element of an array, and an object counts as an array of length one.

But once you cast a pointer to a suitable type, e.g. to a std::uintptr_t (assuming your compiler supports it; it doesn't have to) you can apply any arithmetic you want to it, subject to the constrants imposed upon you by that type.

Although such rules may seem obtuse, they are related to a similar rule where you are not allowed to read a pointer that doesn't point to valid memory. All of this helps achieve greater portability of the language.

like image 23
Bathsheba Avatar answered Nov 12 '22 23:11

Bathsheba