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". Но местоположение никогда не открывается.