деление во время вычитания указателя в C - PullRequest
0 голосов
/ 05 декабря 2018

Рассмотрите приведенный ниже фрагмент кода:

int *p;
/* Lets say p points to address 100 
   and sizeof(int) is 4 bytes. */
int *q = p+1;
unsigned long r = q-p;
/* r results in 1, hence for r = q-p 
   something is happening similar to r=(104-100)/4 */

Существует ли реальное деление на sizeof (тип данных), происходящее во время выполнения, когда вычитаются два указателя одного типа, или существует какой-то другой механизм, посредством которого вычитание указателяработы.

Ответы [ 2 ]

0 голосов
/ 06 декабря 2018

См. Ответ @dbush для объяснения того, как работает вычитание указателя.

Если вместо этого вы программируете что-то низкоуровневое, скажем, ядро, драйвер, отладчик или подобное, и вам нужно иметь фактическое вычитаниеадресов, приведите указатели к char *:

(char *)q - (char *)p

Результат будет иметь тип ptrdiff_t, целое число, определяемое реализацией.

Конечно, это не определено /Portable C, но будет работать на большинстве архитектур / сред.

0 голосов
/ 05 декабря 2018

Стандарт C гласит следующее относительно вычитания указателя (раздел 6.5.6p9):

Когда вычитаются два указателя, оба должны указывать на элементы одного и того же объекта массиваили один за последним элементом массива объекта; В результате получается разница индексов двух элементов массива .Размер результата определяется реализацией, а его тип (целочисленный тип со знаком) ptrdiff_t определен в заголовке.Если результат не может быть представлен в объекте этого типа, поведение не определено.Другими словами, если выражения P и Q указывают, соответственно, на i-й и j-й элементы объекта массива, выражение (P) - (Q) имеет значение i-j, если значение вписывается вобъект типа ptrdiff_t.Более того, если выражение P указывает либо на элемент объекта массива, либо на один элемент после последнего элемента объекта массива, а выражение Q указывает на последний элемент того же объекта массива, выражение ((Q) +1)- (P) имеет то же значение, что и ((Q) - (P)) + 1 и - ((P) - ((Q) +1)), и имеет нулевое значение, если выражение P указывает на одну точку послепоследний элемент объекта массива, хотя выражение (Q) +1 не указывает на элемент объекта массива. 106)

Сноска 106 гласит:

Еще один способ приблизиться к арифметике указателей - сначала преобразовать указатель (и) в символуказатель (и) : в этой схеме целочисленное выражение, добавляемое или вычитаемое из преобразованного указателя, сначала умножается на размер объекта, на который изначально указывался объект, и результирующий указатель преобразуется обратно в исходный тип. Для вычитания указателя результат разницы между символьными указателями аналогично делится на размер объекта, на который первоначально указывался. При таком рассмотрении реализация должна предоставить только один дополнительный байт (который может перекрыватьсядругой объект в программе) сразу после окончания объекта, чтобы удовлетворить требования «один за последним элементом».

Таким образом, в сноске говорится, что вычитание указателя может быть реализованы путем вычитания необработанных значений указателя и деления на размер указываемого объекта.Однако это не обязательно должно быть реализовано таким образом.

Обратите также внимание, что стандарт требует, чтобы вычитание указателя выполнялось между указателями, указывающими на элементы одного и того же объекта массива (или одного элемента после конца).Если они этого не делают, то поведение не определено.На практике, если вы работаете в системе с плоской моделью памяти, вы, вероятно, по-прежнему получите «ожидаемые» значения, но вы не можете зависеть от этого.

...