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

Printf ( "% p" ) и литье в (void *)

В недавнем вопросе кто-то упомянул, что при печати значения указателя с помощью printf вызывающий должен наложить указатель на void *, например:

int *my_ptr = ....

printf("My pointer is: %p", (void *)my_ptr);

В жизни я не могу понять, почему. Я нашел этот вопрос, который почти такой же. Ответ на вопрос правильный - он объясняет, что ints и указатели не обязательно имеют одинаковую длину.

Это, конечно, верно, но когда у меня уже есть указатель, как в приведенном выше случае, почему я должен отбрасывать от int * до void *? Когда int * отличается от void *? Фактически, когда (void *)my_ptr генерирует любой машинный код, отличный от простого my_ptr?

UPDATE: Несколько квалифицированных респондентов цитировали стандарт, говоря, что передача неправильного типа может привести к поведению undefined. Как? Я ожидаю, что printf("%p", (int *)ptr) и printf("%p", (void *)ptr) создадут тот же самый стек-фрейм. Когда два вызова генерируют разные кадры стека?

4b9b3361

Ответ 1

В языке C все типы указателей потенциально различаются по своим представлениям. Итак, да, int * отличается от void *. Платформа реального времени, которая иллюстрирует это различие, может быть трудно (или невозможным) найти, но на концептуальном уровне разница все еще существует.

Другими словами, в общем случае разные типы указателей имеют разные представления. int * отличается от void * и отличается от double *. Тот факт, что ваша платформа использует то же представление для void * и int *, является не чем иным, как совпадением, что касается языка C.

Язык утверждает, что некоторые типы указателей должны иметь одинаковые представления, которые включают в себя void * vs. char *, указатели на разные типы структур или, скажем, int * и const int *. Но это лишь исключения из общего правила.

Ответ 2

p Спецификатор преобразования требует аргумента типа void *. Если вы не передадите аргумент типа void *, вызов функции вызывает поведение undefined.

Из стандарта C:

(C11, 7.21.6.1p8 Форматированные функции ввода/вывода) "p Аргумент должен быть указателем на void."

Типы указателей в C не должны иметь одинаковый размер или одинаковое представление.

Примером реализации с представлением разных типов указателей является Cray PVP, где представление типов указателей является 64-разрядным для void * и char *, но 32-разрядным для других типов указателей.

См. "Справочное руководство Cray C/С++", Таблица 3. в "9.1.2.2" http://docs.cray.com/books/004-2179-003/004-2179-003-manual.pdf

Ответ 3

В действительности, за исключением древних мейнфреймов /minis, разные типы указателей вряд ли имеют разные размеры. Однако они имеют разные типы и для спецификации для printf, вызывая его с неправильным аргументом типа для спецификатора формата в undefined. Это означает, что не делайте этого.

Ответ 4

c11: 7.21.6 Форматированные функции ввода/вывода (p8):

p Аргумент должен быть указателем для void. Значение указателя преобразованный в последовательность печатных символов, в определенном реализацией образом.

Ответ 5

Другие люди адекватно рассмотрели случай передачи int * прототипированной функции с фиксированным числом аргументов, который ожидает другого типа указателя.

printf не является такой функцией. Это вариационная функция, поэтому рекламные объявления по умолчанию используются для анонимных аргументов (т.е. Все после строки формата), и если продвинутый тип каждого аргумента точно не соответствует типу, ожидаемому эффектором формата, поведение undefined. В частности, , даже если int * и void * имеют одинаковое представление,

int a;
printf("%p\n", &a);

имеет поведение undefined.

Это связано с тем, что макет кадра вызова может зависеть от конкретного конкретного типа каждого аргумента. ABI, которые определяют разные области аргументов для типов указателей и не указателей, произошли в реальной жизни (например, Motorola 68000 хотела бы, чтобы вы в максимально возможной степени сохраняли указатели в регистрах адресов и без указателей в регистрах данных). Я не знаю ни одного реального ABI, который разделяет различные типы указателей, но это разрешено, и это не удивит меня услышать об этом.