Разыменование указателя на 0 в C


иногда данные по адресу памяти 0x0 довольно ценны -- возьмите x86 real mode IVT в качестве более известного примера: он начинается с 0x0 и содержит указатели на обработчики прерываний: dword в 0x00-указатель на деление на нулевой обработчик ошибок.

однако стандарт языка C11 запрещает разыменование нулевых указателей [WG14 N1570 6.5.3.2], которые определяются как указатели, инициализированные 0 или указатели, инициализированные нулевым указателем [WG14 N1570 6.3.2.3], эффективно запрещая самый первый байт.

Как люди на самом деле используют 0x0, когда это необходимо?

5 54

5 ответов:

C не запретить разыменование нулевого указателя, это просто делает его неопределенным поведением.

Если ваша среда такова, что вы можете разыменовать указатель, содержащий адрес 0x0, то вы должны быть в состоянии сделать это. Стандарт языка C ничего не говорит о том, что произойдет, когда вы это сделаете. (В большинстве случаев, результатом будет сбой программы.)

конкретный пример (если я правильно помню это): на основе 68k Компьютеры Sun 3, разыменование нулевого указателя не вызывало ловушку; вместо этого ОС хранила нулевое значение в нулевом адресе памяти, а разыменование нулевого указателя (который указывал на нулевой адрес) давало бы это нулевое значение. Это означало, например, что программа на языке C может обрабатывать нулевой указатель, как если бы он был допустимым указателем на пустую строку. Некоторые программы, намеренно или нет, зависели от этого поведения. Это потребовало большой очистки при портировании программного обеспечения на SPARC-based Sun 4, который пойман в ловушку при разыменовании нулевого указателя. (Я отчетливо помню, что читал об этом, но я не смог найти ссылку; я обновлю это, если смогу найти его.)

обратите внимание, что нулевой указатель не обязательно нулевому адресу. Точнее, представление null может быть или не быть all-bits-zero. Это очень часто бывает, но это не гарантировано. (Если это не так, то преобразование целого числа в указатель (void*)0 нетривиальна.)

Раздел 5 comp.ленг.с чаво обсуждаются нулевые указатели.

как люди на самом деле используют 0x0, когда это необходимо?

либо:

  • написание необходимого кода на языке ассемблера, или
  • написание кода на C и проверка того, что их компилятор генерирует правильный язык ассемблера для нужной операции

инструкции:

char * x = 0;

Не обязательно помещает 0x0 в x. он помещает определенное значение нулевого указателя для текущей архитектуры и компилятора в x.

не все нули, и, кто знает, может быть снова.

приложение J это неопределенное поведение, когда...

операнд унарного оператора * имеет недопустимое значение (6.5.3.2).

в той же сноске, которую вы упомянули, говорится, что нулевой указатель является недопустимым значением. Поэтому это не запрещено, а неопределенное поведение. Что касается различия между адресом 0x0 и нулевой указатель, см. можно ли использовать адрес памяти 0x0?.

нулевой указатель не обязательно адрес 0x0, поэтому потенциально an архитектура может выбрать другой адрес для представления null указатель, и вы можете получить 0x0 от new в качестве действительного адреса.

зарезервирован ли нулевой указатель операционной системой или Реализация C++ не указана, но plain new никогда не вернет a нулевой указатель, независимо от его адреса (nothrow new-это другой зверь.) Итак, чтобы ответить на ваш вопрос:

можно ли использовать адрес памяти 0x0?

возможно, это зависит от конкретной реализации/архитектуры.

другими словами, Не стесняйтесь использовать 0x0 Если вы уверены в своей системе, что это не приведет к сбою.

операционная система использует таблицу указателей для прерывания процедур вызова соответствующих прерываний. Как правило (в большинстве операционных систем) таблица указателей хранится в низкой памяти (первые несколько сотен or so locations), эти местоположения содержат адреса процедур обслуживания прерываний для различных устройств.

поэтому, когда вы делаете

char *ptr = 0x0; 

тогда, скорее всего, вы инициализируете свой указатель с адресом службы прерываний обычный. Разыменование (или изменение) ячейки памяти, которая принадлежит операционной системе, скорее всего, приведет к сбою программы.
Так что, лучше не инициализировать указатель на 0x0 и разыменуйте его, пока у вас не будет подтверждения, что он не принадлежит ОС.