@31415
системный инженер

Как на 32-битной платформе в переменную типа intptr_t может влезть максимальный адрес ссылки?

В С++ 11 есть такие типы данных, как знаковый intptr_t (он же ptrdiff_t), и беззнаковый uintptr_t (он же size_t).
en.cppreference.com/w/cpp/types/integer
О ptrdiff_t на сайте PVS-Studio
Утверждается, что что переменные этих типов (intptr_t и uintptr_t ) могут вместить максимально возможное значение адресного пространства, т.е. в нашем примере, 32 бита на 32-битной платформе.
По смыслу, да и в статьях тоже предполагается, что эти два типа фактически равны между собой.
Однако я никак не могу взять в толк: как может БЕЗЗНАКОВОЕ число равняться числу СО ЗНАКОМ?
И, более того, как в ЗНАКОВУЮ переменную типа intptr_t можно поместить 32-битный адрес памяти, если в этом числе 1 бит уходит на знак, а для данных остаётся 31 бит?
И ещё: зачем нужно было вообще вводить intptr_t если есть uintptr_t, в который адрес точно влезет?
  • Вопрос задан
  • 761 просмотр
Решения вопроса 1
@31415 Автор вопроса
системный инженер
Спасибо всем за ответы, они даже, наверно, правильные, но окончательно всё прояснилось, когда мне ответили на Хабре. Привожу сокращённый ответ, вдруг кому понадобится.

Да, действительно, процессор обрабатывает не байты, слова и прочее, а биты и их совокупности разных размеров. Что из себя представляют эти биты - решают разработчики. Чтобы поместить в 8 бит число со знаком, и чтобы можно было с этим числом проводить арифметические операции, разработчики договорились о нескольких форматах хранения. Сначала придумали прямой код, потом обратный, а потом дополнительный. Об этом можно почитать на Википедии.
Так вот, в C\C++ числа со знаком хранятся в дополнительном коде. То есть переменная типа intptr_t будет именно так храниться. Свойства дополнительного кода позволяют нам гарантированно получить разницу между [адресом 2147483640] и [адресом 2147483640+100 байт], даже если [адрес 2147483640+100 байт] превышает максимально допустимый размер в 2147483646 для intptr_t. Это возможно за счёт того, что пространство чисел в дополнительном коде специальным образом закольцовано.
А числа без знака хранятся как uintptr_t в 8 битах в прямом коде, т.е. от 0 до 4294967295. С ними всё понятно и так.
Теперь ответ на вопрос "зачем нужен intptr_t если есть uintptr_t?". uintptr_t нужен, чтобы СРАВНИВАТЬ два указателя. Т.к. числа в нём представлены линейно растущей последовательностью прямого кода, это становится очевидным. При этом сравнивать значения типа intptr_t НЕЛЬЗЯ, т.к. из-за особенностей представления (дополнительный код) указатель на больший адрес может быть представлен битовой последовательностью, которая МЕНЬШЕ, чем указатель на меньший адрес.
Ответ написан
Пригласить эксперта
Ответы на вопрос 2
@Mercury13
Программист на «си с крестами» и не только
зачем нужно было вообще вводить intptr_t если есть uintptr_t, в который адрес точно влезет?

intptr_t — разность двух адресов.

И, более того, как в ЗНАКОВУЮ переменную типа intptr_t можно поместить 32-битный адрес памяти, если в этом числе 1 бит уходит на знак, а для данных остаётся 31 бит?

Учите матчасть — как действует дополнительный код, почему машинные целые изображают в виде круга и почему знаковое и беззнаковое сложение выполняется одними и теми же операциями add/sub. В общем, данные записываются во все 32 бита. И в знаковый тоже.

как может БЕЗЗНАКОВОЕ число равняться числу СО ЗНАКОМ?

А вот сравнивать их — ошибка, и не зря большинство компиляторов выводит предупреждение. Оба надо перевести либо в unsigned, либо в signed, либо в более крупный знаковый целый тип.
Ответ написан
RiseOfDeath
@RiseOfDeath
Диванный эксперт.
зачем нужно было вообще вводить intptr_t если есть uintptr_t, в который адрес точно влезет?


А как вы собираетесь беззанковым типом выражать смешение одного адреса относительно другого?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы