Size_t ptrdiff_t и адресное пространство

В моей системе и ptrdiff_t, и size_t имеют 64-битный.

Я хотел бы прояснить две вещи:

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

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

Не различия указателей, а результат вычитания индекса.

Robert Andrzejuk 20.08.2018 19:04

Для ptrdiff_t "переполнение" размер объекта должен быть 1 (размер символа). Для размера объекта> 2 все в порядке.

Robert Andrzejuk 20.08.2018 19:07

@RobertAndrzejuk, извини, если я недостаточно ясно понял. Я имел в виду: «указатели на элементы массива».

Constantineous 20.08.2018 19:13

Я также хотел обратить ваше внимание (используя кавычки @NathanOliver), так это то, что при определении long long arr[2] вычитание &arr[1] - &arr[0] дает результат 1 (а не 4, как можно было бы ожидать). Итак, чтобы получить эту проблему "переполнения", вы должны иметь дело с необработанной памятью (типы размером 1 байт).

Robert Andrzejuk 21.08.2018 14:11

@RobertAndrzejuk, спасибо, что указали на это!

Constantineous 21.08.2018 18:28

@RobertAndrzejuk Замечание. Можно было бы ожидать, что результат вычитания из вашего примера будет 8, а не 4.

Constantineous 21.08.2018 18:34
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
6
6
554
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

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

If an array is so large (greater than PTRDIFF_MAX elements, but less than SIZE_MAX bytes), that the difference between two pointers may not be representable as std::ptrdiff_t, the result of subtracting two such pointers is undefined.

Ответ принят как подходящий

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

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

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

Верно! Компиляция следующего кода: char array[SIZE_MAX/2+1]; приводит к ошибке: размер массива «array» слишком велик

Constantineous 21.08.2018 16:54

Из [support.types.layout] / 3

The type size_t is an implementation-defined unsigned integer type that is large enough to contain the size in bytes of any object.

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

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

The type ptrdiff_t is an implementation-defined signed integer type that can hold the difference of two subscripts in an array object, as described in 8.7.

Это нормально, но тогда у нас есть [expr.add] / 5

When two pointers to elements of the same array object are subtracted, the type of the result is an implementation-defined signed integral type; this type shall be the same type that is defined as std::ptrdiff_t in the header (21.2). If the expressions P and Q point to, respectively, elements x[i] and x[j] of the same array object x, the expression P - Q has the value i − j; otherwise, the behavior is undefined. [ Note: If the value i − j is not in the range of representable values of type std::ptrdiff_t, the behavior is undefined. —end note ]

Что говорит о том, что ptrdiff_t может быть недостаточно большим.

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