В моей системе и ptrdiff_t, и size_t являются 64-разрядными .

Я хотел бы уточнить две вещи:

  • Я считаю, что ни один массив не может быть таким большим, как size_t из-за ограничений адресного пространства. Это правда?

  • Если да, то есть ли гарантия, что ptrdiff_t сможет содержать результат вычитания любых указателей в массиве максимального размера?

6
Constantineous 20 Авг 2018 в 19:21

3 ответа

Лучший ответ

Большинство реализаций искусственно ограничивают максимальный размер массива, чтобы убедиться, что разница между двумя указателями, указывающими на один и тот же массив, вписывается в ptrdiff_t. Таким образом, более чем вероятно, что на вашей платформе максимально допустимый размер массива равен SIZE_MAX / 2 (попробуйте). Это не «ограничение адресного пространства», это просто ограничение, внутренне примененное вашей реализацией. При этом ограничении вычитание допустимого указателя («legal» = два указателя в одном массиве) не будет переполнено.

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

См. «Три варианта» здесь для получения дополнительной информации: Почему максимальный размер массива слишком велик?

3
AnT 20 Авг 2018 в 17:53

Из [support.types.layout] / 3

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

Таким образом, вы гарантировано, что size_t может содержать размер самого большого массива, который вы можете иметь.

ptrdiff_t к сожалению, это не так гарантировано. Из [support.types.layout] / 2

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

Что хорошо, но тогда у нас есть [expr.add] / 5

Когда вычитаются два указателя на элементы одного и того же объекта массива, тип результата является определяемым реализацией знаковым целочисленным типом; этот тип должен быть того же типа, который определен как std :: ptrdiff_t в заголовке (21.2). Если выражения P и Q указывают соответственно на элементы x [i] и x [j] одного и того же объекта массива x, выражение P - Q имеет значение i - j; в противном случае поведение не определено. [Примечание: если значение i - j не находится в диапазоне представимых значений типа std :: ptrdiff_t, поведение не определено. —Конечная записка]

Который заявляет, что ptrdiff_t может быть недостаточно большим.

3
NathanOliver 20 Авг 2018 в 16:32

Нет, такой гарантии нет. См., Например, здесь: https://en.cppreference.com/w/cpp / типы / ptrdiff_t

Если массив настолько велик (больше, чем элементы PTRDIFF_MAX, но меньше, чем байты SIZE_MAX), что различие между двумя указателями не может быть представлено как std :: ptrdiff_t, результат вычитания двух таких указателей не определен.

4
SergeyA 20 Авг 2018 в 16:27
51934877