Какова мотивация ptrdiff_t?

Почему C определяет отдельный тип для разницы между двумя указателями? Например, почему это нельзя было определить как long long, или даже делать? Есть ли когда-нибудь время, когда intmax_tне равно ptrdiff_t?

В принципе, в чем смысл, почему этот typedef (с определенным строковым форматом и т. д.) полезен? И в качестве основного примера использования я делаю:

      int a = 1, b = 2;
printf("%td XXX\n", (char *)(&b) - (char *)(&a)); // 't' is formatter for prtdiff_t

2 ответа

Есть ли когда-нибудь время, когда не равно ptrdiff_t?

Да, на 32-битных платформах, где указатели 32-битные, и intmax_t>=64-бит.

Вот соответствующий параграф в стандарте C:

6.5.6 Аддитивные операторы
[...]
Семантика
[...]
9. Когда два указателя вычитаются, оба должны указывать на элементы одного и того же объекта массива или один после последнего элемента объекта массива; результатом является разница индексов двух элементов массива. Размер результата определяется реализацией, а его тип (целочисленный тип со знаком) определяется в заголовок. Если результат не может быть представлен в объекте этого типа, поведение не определено. Другими словами, если выражения и указывают соответственно на -й и -th элементов объекта массива, выражение имеет значение при условии, что значение соответствует объекту типа . Более того, если выражение указывает либо на элемент объекта массива, либо на элемент, следующий за последним элементом объекта массива, и выражение указывает на последний элемент того же объекта массива, выражение имеет то же значение, что и и в качестве , и имеет нулевое значение, если выражение указывает один после последнего элемента объекта массива, даже если выражение не указывает на элемент объекта массива. 108)


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

Хотя стандарт C не требует этого, обычно определяется как целочисленный тип со знаком того же размера, что и . В архитектурах, где максимальный размер объекта ограничен 32 битами, таких как 32-битные системы Windows и Unix, это 32-битный целочисленный тип без знака и 32-битный целочисленный тип со знаком, тогда как в 64-битных системах с больше адресного пространства, они оба являются 64-битными целочисленными типами, со знаком и без знака для .

Однако обратите внимание, что разница в 2 указателя на очень большой массив может превышать диапазон знакового типа с тем же размером, что и . Например, массив символов размером 3 ГБ может быть доступен в 32-разрядной системе ( > 3 ГБ), но разница в 2 указателя может достигать 3 ГБ по абсолютной величине, что превышает диапазон , следовательно, соответствует типу этой платформы, вызывая неопределенное поведение.

Большинство реализаций получают разницу путем вычитания адресов и деления результата на размер элемента, используя арифметику со знаком или сдвиг вправо со знаком, если размер является степенью двойки. Это может привести к неправильному результату для больших массивов элементов, превышающих даже если значение соответствует объекту типа .

Обоснование использования типа, определенного реализацией, а не заключается в том, чтобы сохранить совместимость с существующими реализациями и избежать использования более крупных типов в системах с меньшим адресным пространством, где это приведет к дополнительным накладным расходам как по пространству, так и по времени. В ранних реализациях C для этой цели использовался тип. был представлен с потенциально другим диапазоном, чем , конкретный тип для разницы двух указателей стал необходим, поскольку был слишком мал. может быть слишком маленьким, но только для пограничных случаев.

Другие вопросы по тегам