int* p = 0;
int* q = &*p;
Это поведение undefined или нет? Я просмотрел некоторые связанные вопросы, но этот конкретный аспект не появился.
int* p = 0;
int* q = &*p;
Это поведение undefined или нет? Я просмотрел некоторые связанные вопросы, но этот конкретный аспект не появился.
Ответ на этот вопрос: зависит от того, какой язык вы следуете: -).
В C90 и С++ это недопустимо, потому что вы выполняете косвенные действия по нулевому указателю (делая *p), и это приводит к поведению undefined.
Однако в 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является нулевым указателем)
Да, это будет поведение undefined, но ваш компилятор может оптимизировать выход &*.
Почему это его undefined, это то, что вы пытаетесь получить доступ к памяти за пределами вашего адресуемого пространства.
Да, разыменование нулевого указателя имеет поведение undefined. Целочисленная константа 0 в контексте указателя - это нулевой указатель. Что это.
Теперь, если ваша вторая строка была int *q = p;, это было бы простым назначением указателя. Если компилятор удаляет &* и уменьшает разыменование в назначении, вы в порядке.
ИМХО. Что касается двух строк кода, то нет доступа за пределами адресного пространства. Второй оператор просто берет адрес (* p), который будет "p" снова, и, следовательно, он сохранит "0". Но местоположение никогда не открывается.