Ответ 1
В соответствии со спецификацией C:
Целочисленное постоянное выражение со значением 0 или такое выражение cast to type void *, называется константой нулевого указателя. 55) Если нулевой константа указателя преобразуется в тип указателя, в результате указатель, называемый нулевым указателем, гарантированно сравнится неравномерно с указатель на любой объект или функцию.
So 0
- константа нулевого указателя. И если мы преобразуем его в тип указателя, мы получим нулевой указатель, который может быть не-бит-бит для некоторых архитектур. Затем давайте посмотрим, что говорит спецификация сравнения указателей и константы нулевого указателя:
Если один операнд является указатель, а другой - константа нулевого указателя, нулевой указатель константа преобразуется в тип указателя.
Рассмотрим (p == 0)
: сначала 0
преобразуется в нулевой указатель, а затем p
сравнивается с константой нулевого указателя, фактические значения бит которой зависят от архитектуры.
Далее, посмотрите, что говорит спецификация оператора отрицания:
Результат оператора логического отрицания! 0, если значение операнд сравнивается не равным 0, 1, если значение его операнда сравнивается равный 0. Результат имеет тип int. Выражение! E эквивалентно к (0 == E).
Это означает, что (!p)
эквивалентно (p == 0)
, который, согласно спецификации, тестирует p
на заданную машиной константу нулевого указателя.
Таким образом, вы можете спокойно писать if (!p)
даже на архитектурах, где константа нулевого указателя не является битами-ноль.
Как и для С++, константа нулевого указателя определяется как:
Константа нулевого указателя является интегральным постоянным выражением (5.19) prvalue целочисленного типа, который оценивается в 0 или prvalue типа станд:: nullptr_t. Константа нулевого указателя может быть преобразована в указатель тип; результатом является значение нулевого указателя этого типа и отличаться от любого другого значения указателя или функции объекта тип указателя.
Это близко к тому, что у нас есть для C, плюс синтаксический сахар nullptr
. Поведение оператора ==
определяется следующим образом:
Кроме того, можно сравнивать указатели на элементы или указатель на член и константу нулевого указателя. Преобразование указателей в члены (4.11) и квалификационные преобразования (4.4) выполняются для их приведения к общему типу. Если один операнд является константой нулевого указателя, общий тип - это тип другого операнда. В противном случае type - это указатель на тип члена, похожий (4.4) на тип одного из операнды с cv-квалификационной сигнатурой (4.4), которая является объединение cv-квалификационных сигнатур типов операндов. [ Заметка: это означает, что любой указатель на элемент можно сравнить с нулевым постоянная указателя. - конечная нота]
Это приводит к преобразованию 0
в тип указателя (как для C). Для оператора отрицания:
Операнд логического оператора отрицания! контекстуально преобразован в bool (раздел 4); его значение истинно, если преобразованный операнд истинно и false в противном случае. Тип результата - bool.
Это означает, что результат !p
зависит от того, как выполняется преобразование из указателя в bool
. В стандарте говорится:
Значение нуля, значение нулевого указателя или значение указателя нулевого элемента преобразован в false;
Так что if (p==NULL)
и if (!p)
тоже делают то же самое на С++.