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


88

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

void* a = &a;

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

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




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.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.