Как void * a = & a законно?

88

Рассмотрим следующий код C ++:

void* a = &a;

Почему компилятор не жалуется на использование необъявленного идентификатора?

Кроме того, что компилятор считает переменной a? Это указатель на объект void или указатель на void*указатель?

user2681063
источник
6
Пункт декларации
Гриджеш Чаухан
15
Следует упомянуть, почему вы хотите это сделать - чтобы получить указатель на вершину стека (из которого вы можете возиться со всеми видами вещей).
OrangeDog

Ответы:

95

Объем объявления переменных в C ++ может быть довольно удивительным:

void* a =               &a;
         ^~~~~~~~~~~~~~~~~
          a declared as `void*` from here on

Таким образом, &aесть , void**но так как любой тип указателя неявно конвертируется в void*...

Матье М.
источник
Как бы мне присвоить этому полезный объект?
user2681063
22
@ user2681063 a = &userfulObject?
Никос С.
4
@MarkGarcia: обратите внимание, что void *a = a;это будет UB, если объявлено локально, в противном случае это нормально в области пространства имен.
Nawaz
1
@TheodorosChatzigiannakis: Я бы поверил, что да.
Matthieu M.
1
Здесь было бы неплохо сделать ссылку на спецификацию.
Бенджамин Грюнбаум
30

Это эквивалентно

void* a;
a = &a;

Таким образом, aбыло объявлено. Так aполучает адрес aзаписанный в a. Так что это указатель на указатель void. (Вы еще не определили никаких объектов.)

Стасик
источник
9
Технически вы определили один объект. aсам по себе является объектом. (Не все объекты имеют определяемые пользователем типы в C ++)
MSalters
1
@MSalters, что это за «объект», о котором вы говорите? : D
Gusdor
3
@Gusdor Мы можем только предполагать, что находится за пределами горизонта событий.
Коул Джонсон,
Они называются по-разному, однако «эффект» в этом случае тот же
Стасик
В целом они не эквивалентны, но в этом сценарии они есть.
Гонки за легкостью на орбите,
7

В void* a, aобъявлен как указатель не к voidтипу , а к «любой» типа (частный случай). Адрес (позиция в памяти) присваивается a, как и любой другой объявленной переменной, конечно.

После этого выражение &aвычисляется для инициализации только что объявленной переменной (также a, но это не имеет значения). Типом &aявляется «указатель на указатель на любой тип», который является частным случаем «указателя на любой тип», полностью совместимого с типом a. Ergo, нет сообщения компилятора.

Следствие: не используйте, void*если хотите строгую проверку типов. В него можно преобразовать все что угодно . Как раз наоборот, в обратном направлении, кроме void*самого себя (было бы ненужным исключением, если бы тип был несовместим сам с собой).

Кроме того, AFAIR это действительно исходит от C.

Марио Росси
источник