В моей системе и ptrdiff_t
, и size_t
являются 64-разрядными .
Я хотел бы уточнить две вещи:
Я считаю, что ни один массив не может быть таким большим, как
size_t
из-за ограничений адресного пространства. Это правда?Если да, то есть ли гарантия, что
ptrdiff_t
сможет содержать результат вычитания любых указателей в массиве максимального размера?
3 ответа
Большинство реализаций искусственно ограничивают максимальный размер массива, чтобы убедиться, что разница между двумя указателями, указывающими на один и тот же массив, вписывается в ptrdiff_t
. Таким образом, более чем вероятно, что на вашей платформе максимально допустимый размер массива равен SIZE_MAX / 2
(попробуйте). Это не «ограничение адресного пространства», это просто ограничение, внутренне примененное вашей реализацией. При этом ограничении вычитание допустимого указателя («legal» = два указателя в одном массиве) не будет переполнено.
Спецификация языка не требует этого, хотя. Реализации не обязаны таким образом ограничивать размер своего массива, а это означает, что языковая спецификация допускает переполнение, казалось бы, допустимых вычитаний указателя и приводит к неопределенному поведению. Но большинство реализаций предпочитают защищаться от этого, ограничивая размеры своих массивов.
См. «Три варианта» здесь для получения дополнительной информации: Почему максимальный размер массива слишком велик?
Из [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
может быть недостаточно большим.
Нет, такой гарантии нет. См., Например, здесь: https://en.cppreference.com/w/cpp / типы / ptrdiff_t
Если массив настолько велик (больше, чем элементы PTRDIFF_MAX, но меньше, чем байты SIZE_MAX), что различие между двумя указателями не может быть представлено как std :: ptrdiff_t, результат вычитания двух таких указателей не определен.
Связанные вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который будет скомпилирован с помощью компилятора C ++). Используйте тег, зависящий от версии, для вопросов, связанных с конкретной редакцией стандарта [C ++ 11], [C ++ 14], [C ++ 17] или [C ++ 20] и т. Д.