Это нулевые указатели или они указывают на адрес 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 (редактировать: я добавил p8 а также p9) будут нулевыми указателями (т.е. == NULL, может быть или не быть адресом ноль), и какие из них будут указателями с адресом ноль (может или не может быть == NULL)?

Если ответ различается в C и C++, что в каждом из них?

3 ответа

Решение

p1 а также p2 нулевые указатели; p3 определяется реализацией и может быть чем-то другим. (Оператор запятой не может быть частью константного выражения. А отображение непостоянного целочисленного значения 0 на указатель определяется реализацией.) Здесь C идентично C++.

p8 а также p9 оба являются нулевыми указателями в C++, но не в C.

Что касается вашего комментария static_zero_2ни на одном языке не требуется, чтобы буквальный ноль присутствовал где-либо. g ++ определяет NULL как встроенный компилятор __nullНапример, и вы можете использовать (1 - 1), или же '\0'или любое другое константное выражение с оценкой 0.

И чтобы завершить ответ Энди с C:

Из стандарта C99:

6.3.2.3. Указатели

1 Указатель на void может быть преобразован в или из указателя на любой неполный или объектный тип. Указатель на любой неполный или тип объекта может быть преобразован в указатель на void и обратно; результат должен сравниваться равным исходному указателю.

3 Целочисленное константное выражение со значением 0 или такое выражение приведено к типу void *, называется константой нулевого указателя. 55) Если константа нулевого указателя преобразуется в тип указателя, результирующий указатель, называемый нулевым указателем, гарантированно сравнивается с неравным указателем на любой объект или функцию.

Таким образом, любое целочисленное константное выражение, которое оценивает 0 является константой нулевого указателя и может быть преобразована в NULL указатель. Эффективно в вашем примере все указатели, кроме p4, p8 а также p9 нулевые указатели. p4, p8 а также p9 не должны быть нулевыми указателями, так как их инициализация не является константным выражением, поскольку содержит переменные (даже если const Квалифицированный).

Вот еще один ответ о NULL в C++, для записи.

какой из p1, p2, а также p3 будут нулевые указатели?

В C++11 все они. В соответствии с пунктом 4.10/1 стандарта C++11:

Константа нулевого указателя - это целочисленное константное выражение (5.19) prvalue целочисленного типа, которое оценивается как ноль или prvalue типа std::nullptr_t, [...]

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

Абзац продолжается:

Константа нулевого указателя может быть преобразована в тип указателя; результат является нулевым значением указателя этого типа и отличается от любого другого значения указателя объекта или типа указателя функции. Такое преобразование называется преобразованием нулевого указателя. Два значения нулевого указателя одного типа должны сравниваться одинаково.

Так что в вашем примере все указатели, кроме p4 являются нулевыми значениями указателя и сравниваются равными между собой.

Другие вопросы по тегам