диапазон - типы данных c




Спецификатору формата% p требуется явное приведение к void*для всех типов, кроме char*в printf (3)

Для аргументов типа char* явное приведение не требуется, поскольку char * имеет такое же представление и требование выравнивания, что и void * .

Цитата C11 , глава §6.2.5

Указатель на void должен иметь те же требования к представлению и выравниванию, что и указатель на символьный тип. (48) [...]

и сноска 48)

Те же требования к представлению и выравниванию подразумевают взаимозаменяемость в качестве аргументов функций, возвращаемых значений функций и членов объединений.

Я прочитал много ответов об использовании спецификатора формата %p на языке C здесь, в Переполнении стека, но ни один из них не дает объяснения, почему явное приведение к void* необходимо для всех типов, кроме char* .
Я, конечно, осведомлен о том факте, что это требование приведения в или из void* связано с использованием функций с переменным числом (см. Первый комментарий к этому answer ), в то время как в противном случае оно не является обязательным.

Вот пример:

int i;    
printf ("%p", &i);

Выдает предупреждение о несовместимости типов и о том, что &i должно быть преобразовано в void* (как требуется стандартом, см. Снова here ).

Принимая во внимание, что этот кусок кода компилируется без каких-либо жалоб на приведение типов:

char * m = "Hello";    
printf ("%p", m);

Как получилось, что char* «освобожден» от этого императива?

PS : Возможно, стоит добавить, что я работаю над архитектурой x86_64 , так как от нее зависит размер типа указателя, и использую gcc в качестве компилятора в linux с -W -Wall -std=c11 -pedantic .


Из стандарта C # 6.2.5p28

Указатель на void должен иметь те же требования к представлению и выравниванию, что и указатель на тип символа.48) Аналогично, указатели на квалифицированные или неквалифицированные версии совместимых типов должны иметь те же требования к представлению и выравниванию. Все указатели на типы конструкций должны иметь те же требования к представлению и выравниванию, что и другие. Все указатели на типы объединения должны иметь те же требования к представлению и выравниванию, что и другие. Указатели на другие типы не обязательно должны иметь одинаковые требования к представлению или выравниванию. [акцент мой]


Стандарт C11 6.2.5 / 28 гласит:

Указатель на void должен иметь те же требования к представлению и выравниванию, что и указатель на символьный тип. 48)

сноска 48:

Те же требования к представлению и выравниванию подразумевают взаимозаменяемость в качестве аргументов функций , возвращаемых значений функций и членов объединений.

Однако 7.21.6.1 («Функция fprintf») говорит о %p :

Аргумент должен быть указателем на void.

Это, по-видимому, противоречие. На мой взгляд, разумная интерпретация состоит в том, чтобы сказать, что цель 6.2.5 / 28 состоит в том, что void * и char * фактически взаимозаменяемы как типы для аргументов функции, которые не соответствуют прототипу. (т. е. аргументы для функций, не являющихся прототипами, или совпадение с многоточием прототипа функции с переменными координатами).

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

Чтобы подкрепить это, спецификация типов аргументов в 7.21.6.1, если она воспринимается буквально без учета намерения, имеет много других несоответствий, которые необходимо игнорировать на практике (например, она говорит, что printf("%lx", -1); четко определен, но printf("%u", 1); неопределенное поведение).







void-pointers