Может ли 32-разрядный процессор действительно адресовать 2^32 места памяти?


Я чувствую, что это может быть странный/глупый вопрос,но вот он...

В вопросе является ли NULL в C обязательным / определенным нулем?, было установлено, что указатель NULL указывает на неадресируемую область памяти, а также что NULL является 0.

Теперь, предположительно, 32-разрядный процессор может обращаться к 2^32 местам памяти.

2^32 это только число различных чисел, которые могут быть представлены с помощью битов 32. Среди этих чисел есть 0. Но поскольку 0, то есть NULL, должен указывать на ничто, не следует ли нам сказать, что 32-разрядный процессор может обращаться только к 2^32 - 1 местам памяти (поскольку 0 не должен быть допустимым адресом)?

4 7

4 ответа:

Нулевой указатель указывает на неадресируемую область памяти

Это не так. Из принятого ответа в вопросе, который вы связали:

Обратите внимание, что из-за того, как сформулированы правила для нулевых указателей, значение, которое вы используете для назначения / сравнения нулевых указателей, гарантированно равно нулю, но битовый шаблон, фактически хранящийся внутри указателя, может быть любым другим

Большинство платформ, о которых я знаю, действительно справляются с этим, помечая первые несколько страниц адресного пространства недопустимы. Это не означает, что процессор не может обращаться к таким вещам; это просто удобный способ сделать низкие значения недопустимым указателем. Например, некоторые API Windows используют это для различения идентификатора ресурса и указателя на фактические данные; все, что ниже определенного значения (65k, если я правильно помню), не является допустимым указателем, но является допустимым идентификатором ресурса.

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

Если 32-разрядный процессор может обращаться к 2^32 ячейкам памяти, это просто означает, что указатель C на этой архитектуре может ссылаться на 2^32 - 1 ячейки плюс NULL.

Во-первых, отметим разницу между линейным адресом (он же значение указателя) и физическим адресом. В то время как линейное адресное пространство, действительно, 32 бита (AKA 2^32 различных байта), физический адрес, который идет к чипу памяти, не является тем же самым. Части ("страницы") линейного адресного пространства могут быть сопоставлены с физической памятью, или с файлом подкачки, или с произвольным файлом, или помечены как недоступные и ничем не подкрепленные. Нулевая страница оказывается последней. То механизм отображения реализован на уровне процессора и поддерживается ОС.

Тем не менее, нулевой адрес, являющийся неадресируемой памятью,-это всего лишь соглашение C, которое применяется каждой ОС защищенного режима со времен первых Юнисов. В системах реального времени MS-DOS-era нулевой дальний указатель (0000:0000) был идеально адресуемым; однако запись там разрушила бы структуры системных данных и не принесла бы ничего, кроме проблем. Нулевой Ближний указатель (DS: 0000) также был отлично доступен, но время выполнения библиотека обычно резервирует некоторое пространство вокруг нуля для защиты от случайного разыменования нулевого указателя. Кроме того, в реальном режиме (как и в DOS) адресное пространство не было плоским 32-битным, оно было фактически 20-битным.

Это зависит от операционной системы. Он связан с виртуальной памятью и адресными пространствами

На практике (по крайней мере, в Linux x86 32 бит) адреса являются байтовыми "числами", но большинство из них предназначены для 4-байтовых слов, поэтому часто кратны 4.

И что еще более важно, Как видно из Приложения Linux, только Самое большее 3 Гбайт из 4 Гбайт видно. целый гигабайт адресного пространства (включая первую и последнюю страницы, рядом с нулевым указателем) - это неотображаемый. На практике процесс видит гораздо меньше этого. Смотрите его псевдофайл /proc/self/maps (например, запустите cat /proc/self/maps, чтобы увидеть адресную карту команды cat в Linux).