Являются ли эти нулевые указатели, или они указатели на адрес 0?
Если я пишу
int zero = 0;
void *p1 = (void *)0;
void *p2 = (void *)(int)0;
void *p3 = (void *)(0 /*no-op, but does it affect the next zero?*/, 0);
void *p4 = (void *)zero; // For reference, this is a pointer to address zero
void *p5 = 0; // For reference, this is a null pointer
void *p6 = NULL; // For reference, this is a null pointer
void *p7 = nullptr; // For reference, this is a null pointer (C++11)
static const int static_zero_1 = 0; // Is this a literal zero when used?
static const int static_zero_2 = 1 - 1; // No "literals 0" per se... is it?
void *p8 = (void *)static_zero_1; // I have seen weird substitution rules...
void *p9 = (void *)static_zero_2; // do they apply for NULL too?
который из p1
, p2
и p3
( edit: Я добавил p8
и p9
) был бы нулевым указателем (т.е. == NULL
, может или может не быть нулевым адресом), и какие из них будут указателями с нулевым адресом (может или не может быть == NULL
)?
Если ответ отличается в C и С++, что это такое в каждом из них?
Ответы
Ответ 1
p1
и p2
- нулевые указатели; p3
определяется реализация,
и может быть что-то еще. (Оператор запятой не может быть частью
постоянное выражение. И отображение непостоянного
целочисленное значение 0 для указателя определяется реализацией.) C является
здесь идентичен С++.
p8
и p9
являются нулевыми указателями в С++, но не в C.
Что касается вашего комментария по static_zero_2
, то нет
требование на любом языке, чтобы присутствовал буквальный ноль,
в любом месте. g++ определяет NULL
как встроенный компилятор __null
,
например, и вы можете использовать (1 - 1)
, или '\0'
, или любые другие
постоянное выражение, оценивающее 0.
Ответ 2
И чтобы Энди ответил в комплекте с C:
Из стандарта C99:
6.3.2.3 Указатели
1 Указатель на void может быть преобразован в указатель или из указателя на любой неполный или объект тип. Указатель на любой неполный или тип объекта может быть преобразован в указатель на void и обратно; результат сравнивается с исходным указателем.
3 целочисленное константное выражение со значением 0
, или такое выражение, отлитое для типа void *
, называется константой нулевой указатель. 55) Если константа нулевого указателя преобразуется в тип указателя, полученный указатель, называемый нулевым указателем, гарантированно сравнивает неравные к указателю на любой объект или функцию.
Таким образом, любое целочисленное константное выражение, которое оценивается как 0
, является константой нулевого указателя и может быть преобразовано в указатель NULL
. Эффективно в вашем примере все указатели за исключением p4
, p8
и p9
являются нулевыми указателями. p4
, p8
и p9
не обязательно должны быть нулевыми указателями, поскольку их инициализация не является константным выражением, поскольку содержит переменные (даже если const
квалифицирован).
Вот еще один ответ о NULL
в С++ для записи.
Ответ 3
который из p1
, p2
и p3
будет нулевым указателем?
В С++ 11 все они. За абзац 4.10/1 стандарта С++ 11:
Константа нулевого указателя является интегральным постоянным выражением (5.19) prvalue целочисленного типа, которое оценивается ноль или значение типа std::nullptr_t
. [...]
Поэтому, согласно терминологии Стандарта, все, что является постоянным (интегральным) выражением и оценивается как 0
, является константой нулевой указатель (но не нулевым указателем). Единственный, который не является постоянным выражением, которое оценивается как 0
или prvalue типа nullptr_t
в вашем примере, это zero
, потому что это не постоянное выражение.
Параграф продолжается:
Константа нулевого указателя может быть преобразована в тип указателя; результатом является нулевое значение указателя этого типа и отличается от любого другого значения указателя объекта или тип указателя функции. Такое преобразование называется преобразованием нулевого указателя. Два значения нулевого указателя одинаковый тип должен сравниваться с равным.
Итак, в вашем примере все указатели, кроме p4
, являются значениями нулевого указателя и сравниваются между собой.