Может ли 32-разрядный процессор действительно адресовать 2^32 места памяти?
Я чувствую, что это может быть странный/глупый вопрос,но вот он...
В вопросе является ли NULL в C обязательным / определенным нулем?, было установлено, что указатель NULL
указывает на неадресируемую область памяти, а также что NULL
является 0
.
2^32
местам памяти.
2^32
это только число различных чисел, которые могут быть представлены с помощью битов 32
. Среди этих чисел есть 0
. Но поскольку 0
, то есть NULL
, должен указывать на ничто, не следует ли нам сказать, что 32-разрядный процессор может обращаться только к 2^32 - 1
местам памяти (поскольку 0
не должен быть допустимым адресом)?
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).