Is subtraction of non-divisible pointer addresses defined in C? In C++?
Here's an example:
void* p = malloc(64);
int* one = (int*)((char*)p);
int* two = (int*)((char*)p + 7);
printf("%x %x %d %d\n", one, two, sizeof(int), two - one);
Ideone link.
I get the output 8a94008 8a9400f 4 1
, so it seems like it does the division and truncates the remainder. Is the behavior defined?
The subtraction of two pointers is possible only when they have the same data type. The result is generated by calculating the difference between the addresses of the two pointers and calculating how many bits of data it is according to the pointer data type.
Two pointers can also be subtracted from each other if the following conditions are satisfied: Both pointers will point to elements of same array; or one past the last element of same array. The result of the subtraction must be representable in ptrdiff_t data type, which is defined in stddef.
Because pointers represent locations in the memory. Each pointer is the address of a block in the memory. Subtracting two pointers will give you the size of memory between them. Addition or any other mathematical operation on values of pointers has no meaning.
If we perform addition, multiplication, division or modulus on ptr_1 and ptr_2, then the resultant address may or may not be a valid address. That can be out of range or invalid address. This is the reason compiler doesn't allow these operations on valid addresses.
This is undefined behavior according to 5.7.6:
When two pointers to elements of the same array object are subtracted, the result is the difference of the subscripts of the two array elements. [...] Unless both pointers point to elements of the same array object, or one past the last element of the array object, the behavior is undefined.
In your code, pointer two
is not pointing to an element of the same int
array as pointer one
. In fact, it is not pointing to any array element of p
, because it points to the "middle" of one of the elements (which in itself is an undefined behavior).
Under some assumptions1, in C the third line:
int* two = (int*)((char*)p + 7);
already causes undefined behavior, because the pointer p isn't correctly aligned for the type it is referencing2.
1 The assumption is that alignment requirements for type int are be higher than for type char. This is true on most moderns architectures. Since all alignments must be powers of two3 and the value 7 isn't, the addition of that value to the pointer p cannot produce a pointer with an alignment that is as strict as is the alignment requirement for type int.
2 (Quoted from: ISO/IEC 9899:201x 6.3.2.3 Pointers 7.)
A pointer to an object type may be converted to a pointer to a different object type. If the
resulting pointer is not correctly aligned for the referenced type, the behavior is
undefined.
3 (Quoted from: ISO/IEC 9899:201x 6.2.8 Alignment of objects 4.)
Every valid
alignment value shall be a nonnegative integral power of two.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With