Вопрос: Как "получить" нулевой указатель в программе?

Ответ:

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

Следовательно, следующий фрагмент абсолютно корректен:
  char *p = 0;
  if(p != 0)

Однако, аргумент, передаваемый функции, не обязательно будет распознан как значение указателя, и компилятор может оказаться не способным распознать голый 0 как нулевой указатель. Например, системный вызов UNIX "execl" использует в качестве параметров переменное количество указателей на аргументы, завершаемое нулевым указателем. Чтобы получить нулевой указатель при вызове функции, обычно необходимо явное приведение типов, чтобы 0 воспринимался как нулевой указатель.
  execl("/bin/sh", "sh", "-c", "ls", (char *)0);

Если не делать преобразования (char *), компилятор не поймет, что необходимо передать нулевой указатель и вместо этого передаст число 0. (Заметьте, что многие руководства по UNIX неправильно объясняют этот пример.)

Когда прототипы функций находятся в области видимости, передача аргументов идет в соответствии с прототипом и большинство приведений типов может быть опущено, так как прототип указывает компилятору, что необходим указатель определенного типа, давая возможность правильно преобразовать нули в указатели. Прототипы функций не могут, однако, обеспечить правильное преобразование типов в случае, когда функция имеет список аргументов переменной длины, так что для таких аргументов необходимы явные преобразования типов.
Всегда безопаснее явные преобразования в нулевой указатель,
— чтобы не наткнуться на функцию с переменным числом аргументов или на функцию без прототипа,
— чтобы временно использовать не-ANSI компиляторы,
— чтобы продемонстрировать, что Вы знаете, что делаете. (Кстати, самое простое правило для запоминания.)

Итог:
Можно использовать 0       |  Необходимо преобразование
---------------------------+---------------------------
инициализация              |  вызов функции, прототип которой
                           |  вне области видимости
присваивание               |
                           |  переменное число аргументов
сравнение                  |  при вызове функции
                           |
вызов функции, прототип    |
в области видимости,       |
количество аргументов      |
фиксировано                |


Смотри:
K&R I Разд. A7.7 c. 190, Разд. A7.14 c. 192;
K&R II Разд. A7.10 c. 207, Разд. A7.17 c. 209;
H&S Разд. 4.6.3 c. 72;
ANSI Разд. 3.2.2.3 .
Автор: Кодт    Оценить