Подтвердить что ты не робот

Препроцессор C удаляет экземпляры "& *"?

Я играл с gcc и пробовал следующий бит кода:

int A = 42;
int *B = &A;
int *C = &*B;

И C == &A, как и ожидалось. Но когда я пытаюсь:

int *B = NULL;
int *C = &*B;

Выключает C == NULL, а не segfault. Таким образом, &*B не является разыменованием B, прежде чем принимать его адрес.

Я предполагаю, что препроцессор удаляет экземпляры &* и *&, прежде чем они даже попадут в компилятор, поскольку они отрицают друг друга, но я не могу найти документацию, чтобы проверить, является ли это стандартным C или компилятор конкретного.

Заканчивается ли препроцессор &* и *&, и можно ли ожидать этого поведения от любого данного компилятора?

4b9b3361

Ответ 1

Это не убирает предварительный процесс, &* просто заканчивается эквивалентом самого указателя, мы можем это увидеть, перейдя в проект стандарта C99 6.5.3.2 Операторы адреса и косвенности, указанные в пункте 4, в котором говорится:

Унарный * оператор обозначает косвенность. Если операнд указывает на функцию, результат обозначение функции; если он указывает на объект, результатом является значение l, обозначающее объект. Если операнд имеет тип '' указатель на тип, результат имеет тип ''. Если недопустимое значение было присвоено указателю, поведение унарного * оператора undefined. 87)

и в сноске 87 говорится:

Таким образом, & * E эквивалентно E (даже если E является нулевым указателем), [...]

и в пункте 3 говорится (внимание мое):

Унарный и оператор дает адрес своего операнда. Если операнд имеет тип типа '', результат имеет тип '' указатель на тип. Если операнд является результатом унарного * оператора, ни тот оператор, ни оператор и не оцениваются, и результат выглядит так, как если бы оба были omitted, за исключением того, что ограничения на операторы все еще применяются, и результат не является значением l.

Обновить

Возможно, стоит отметить, что для gcc и clang вы можете просмотреть результаты предварительной обработки, используя флаг -E (см. его в прямом эфире) и в Visual Studio fooobar.com/questions/34399/... (посмотреть в прямом эфире).

Кроме того, стоит отметить, что, как сказал MSalters в своем комментарии, просто наличие двух токенов &* недостаточно для понимания контекста, как показывает его пример:

int *p, *q ;
int foo = *p & *q ;

Таким образом, просто удаление &* даже не было бы возможным на этапе предварительной обработки, поскольку у вас не было бы достаточной информации, чтобы определить, был ли & адресом оператора или побитового оператора.

Ответ 2

Препроцессор не достигает &*. Тем не менее, стандарт C 2011 гласит в 6.5.3.2 3, около &:

Если операнд [из &] является результатом унарного оператора *, ни этот оператор, ни оператор & не являются и результат будет таким, как если бы оба были опущены, за исключением того, что ограничения на операторы все еще применяются, и результат не является lvalue.

В соответствии с ограничениями, упомянутыми выше, операнд * должен иметь тип указателя. Таким образом, &*3 не изменяется на 3 этим пунктом; он нарушает ограничения, потому что 3 не имеет типа указателя. Кроме того, &*x не изменяется до x, так как результат не является значением lvalue. Например, это недопустимо:

int a, *x;
x   = &a; // Normal, allowed.
&*x = &a; // Not allowed; `&*x` does not became exactly the same as `x`.