разыменование нулевого указателя

int* p = 0;
int* q = &*p;

Это неопределенное поведение или нет? Я просмотрел некоторые связанные вопросы, но этот определенный аспект не обнаружился.

24
задан fredoverflow 24 May 2010 в 11:43
поделиться

4 ответа

Ответ на этот вопрос: это зависит от того, какой языковой стандарт вы используете :-).

В 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 является нулевым указателем )

50
ответ дан 28 November 2019 в 23:10
поделиться

Да, это будет неопределенное поведение, но ваш компилятор может оптимизировать выход & * .

Почему он не определен, заключается в том, что вы пытаетесь получить доступ к памяти за пределами адресного пространства.

3
ответ дан 28 November 2019 в 23:10
поделиться

ИМХО, что касается двух строк кода, нет никакого доступа за пределами адресное пространство. Второй оператор просто берет адрес (* p), который снова будет «p», и, следовательно, он будет хранить «0». Но это местоположение никогда не доступно .

-1
ответ дан 28 November 2019 в 23:10
поделиться

Да, разыменование нулевого указателя - это неопределенное поведение. Целочисленная константа 0 в контексте указателя - это нулевой указатель. Вот и все.

Теперь, если бы ваша вторая строка была int *q = p;, это было бы простое присвоение указателя. Если компилятор удалит &* и сведет разыменование к присваиванию, то все будет в порядке.

-1
ответ дан 28 November 2019 в 23:10
поделиться