Ответ 1
Чтобы ответить на вопрос напрямую, нет, нет обязательного правила, определения, стандарта или спецификации, в которых (void *) -1
не может быть действительным адресом.
(Конечно, никаких правил, определений, стандартов или спецификаций адресов памяти не обязательно. Я вижу, что люди ходят по улице каждый день, не соблюдая, например, стандарт C, но я никогда не видел, чтобы кто-то арестовывал за это Но даже если мы опускаем обязательную часть, использование (void *) -1
в качестве адреса, как правило, не запрещено стандартными спецификациями.)
Однако для того, чтобы shmat не работал, не нужно, чтобы (void *) -1
не был действительным адресом. Просто необходимо, чтобы успешный вызов shmat никогда не возвращал (void *) -1
и чтобы (void *) -1
поддерживался компилятором для тестирования возвращаемого значения из shmat. Если эти два условия выполнены, то программа всегда может отличить успешный вызов shmat от неудачного вызова shmat.
Что касается второго условия, стандарт C не гарантирует, что (void *) -1
может использоваться, поэтому POSIX, указав, что это возврат ошибки из shmat, неявно требует реализации C (или другого языка) для его поддержки. Таким образом, это расширение языка, требуемого POSIX, и, как правило, это просто для компиляторов.
Что касается первого условия, подумайте, когда мы хотим, чтобы shmat вернул (void *) -1
для успешного вызова. shmat можно вызвать с запрошенным пользователем адресом или без него, и в этом случае реализация выбирает адрес. В любой нормальной компьютерной архитектуре существует несколько причин использовать адреса, кратные различным значениям. Для shmat наиболее очевидным является отображение памяти. На архитектурах с виртуальной памятью память отображается в единицах страниц, а shmat, когда она отображает память для сегмента, будет отображаться на начало страницы. Любой ровный размер страницы не имеет кратных значений (void *) -1
, так как последний нечетный, поэтому shmat никогда не выбирает отображение сегмента на (void *) -1
. Даже если shmat не использовал размер страницы, он обычно использовал бы другое выравнивание, такое как 4, 8 или 16 байт, потому что предоставление выровненной памяти означает, что структуры, сохраненные в начале этой памяти, будут выровнены, что приведет к более быстрой памяти доступ на многие процессоры.
Это оставляет случай, когда пользователь запрашивает (void *) -1
в качестве адреса. Это было бы необычно, и это могло бы работать только в том случае, если сегмент памяти был одним байтом или модель памяти позволяла обертывать (или компилятор представил очень странную модель памяти, в которой (void *) -1
не был последним байтом в адресном пространстве), Я не могу точно сказать, поддерживают ли какие-либо POSIX-системы это или нет. Однако ясно, что это по сути бесполезно, и никто не имеет никаких оснований для этого, кроме любопытства. Таким образом, безопасно и разумно управлять этим случаем из shmat, просто говоря, что это не поддерживается, не делайте этого.