Подтвердить что ты не робот

Вычитание недискретных указательных адресов

Вычитание непересекающихся адресов указателей, определенных в C? В С++?

Вот пример:

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

Идеальная ссылка.

Я получаю вывод 8a94008 8a9400f 4 1, поэтому кажется, что он разделяет и обрезает остаток. Определено ли поведение?

4b9b3361

Ответ 1

Это поведение undefined в соответствии с 5.7.6:

Когда два указателя на элементы одного и того же объекта массива вычитаются, результатом является разность индексов двух элементов массива. [...] Если оба указателя не указывают на элементы одного и того же объекта массива или один за последним элементом объекта массива, поведение undefined.

В вашем коде указатель two не указывает на элемент того же массива int как указатель one. Фактически, он не указывает на какой-либо элемент массива из p, поскольку он указывает на "середину" одного из элементов (который сам по себе является undefined).

Ответ 2

При некоторых предположениях 1 в C третья строка:

int* two = (int*)((char*)p + 7);

уже вызывает поведение undefined, потому что указатель p неправильно выровнен для типа, на который он ссылается 2.


1 Предполагается, что требования к выравниванию для типа int будут выше, чем для типа char. Это справедливо для большинства современных архитектур. Так как все выравнивания должны иметь силу двух 3 а значение 7 - нет, добавление этого значения в указатель p не может создать указатель с выравниванием, которое является настолько строгим, как требование выравнивания для тип int.

2 (Цитируется по: ISO/IEC 9899: 201x 6.3.2.3 Указатели 7.)
Указатель на тип объекта может быть преобразован в указатель на другой тип объекта. Если полученный указатель неправильно выровнен для ссылочного типа, поведение undefined.

3 (Цитируется по: ISO/IEC 9899: 201x 6.2.8 Выравнивание объектов 4.)
Все действующие значение выравнивания должно быть неотрицательной интегральной степенью двух.