Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Subtraction of non-divisible pointer addresses

Tags:

c++

c

pointers

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?

like image 659
Paul Avatar asked Mar 16 '16 08:03

Paul


People also ask

Can we subtract two addresses in pointer?

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.

How do you subtract a pointer from a pointer?

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.

Why 2 pointers can not be added multiplied or divided but can only be subtracted?

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.

Why division is not possible in pointer?

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.


2 Answers

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).

like image 104
Sergey Kalinichenko Avatar answered Sep 18 '22 06:09

Sergey Kalinichenko


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.

like image 24
2501 Avatar answered Sep 21 '22 06:09

2501