int* p = 0;
int* q = &*p;
Это неопределенное поведение или нет? Я просмотрел некоторые связанные вопросы, но этот определенный аспект не обнаружился.
Ответ на этот вопрос: это зависит от того, какой языковой стандарт вы используете :-).
В C90 и C ++ это недопустимо, поскольку вы выполняете косвенное обращение к нулевому указателю (выполняя * p
), и это приводит к неопределенному поведению.
Однако в C99 этот является действительным, правильно сформированным и четко определенным. В C99, если операнд унарного- &
был получен в результате применения унарного- *
или выполнения индексации ([]
), то ни &
, ни *
или []
не применяются. Например:
int* p = 0;
int* q = &*p; // In C99, this is equivalent to int* q = p;
Аналогично,
int* p = 0;
int* q = &p[0]; // In C99, this is equivalent to int* q = p + 0;
Из C99 §6.5.3.2/3:
Если операнд [унарного оператора
&
] является результатом унарного оператора*
, ни этот оператор, ни&
оценивается, и результат такой, как если бы оба были опущены, за исключением того, что ограничения на операторы все еще применяются, и результат не является lvalue.Аналогичным образом, если операнд является результатом оператора
[]
, ни оператор&
, ни унарный*
, подразумеваемый[]
, не оценивается, и результат такой, как если бы оператор&
был удален, а оператор[]
заменен на оператор+
.
(и его сноска, # 84):
Таким образом,
& * E
эквивалентноE
(даже еслиE
является нулевым указателем )
Да, это будет неопределенное поведение, но ваш компилятор может оптимизировать выход & *
.
Почему он не определен, заключается в том, что вы пытаетесь получить доступ к памяти за пределами адресного пространства.
ИМХО, что касается двух строк кода, нет никакого доступа за пределами адресное пространство. Второй оператор просто берет адрес (* p), который снова будет «p», и, следовательно, он будет хранить «0». Но это местоположение никогда не доступно .
Да, разыменование нулевого указателя - это неопределенное поведение. Целочисленная константа 0 в контексте указателя - это нулевой указатель. Вот и все.
Теперь, если бы ваша вторая строка была int *q = p;
, это было бы простое присвоение указателя. Если компилятор удалит &*
и сведет разыменование к присваиванию, то все будет в порядке.