2014-11-05 4 views
13

Я слышал, что указатели сначала должны быть отброшены до void для обеспечения согласованности значений на разных платформах и должны использовать спецификатор формата %p. Почему это и какие именно проблемы?Использование указателей void на разных платформах

int x=100; 
int *pi=&x; 
printf("value of pi is: %p",(void*)pi); 

ответ

13

printf является VARIADIC функции и должны быть переданы аргументы правых типов. В стандарте говорится, что %p принимает void *.

Implicit cast doesn't take place для variadic functions.

Цитируя N15707.21.6.1 Функция fprintf

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

+0

Обратите внимание на то, что ваша цитата, безусловно, относится к POSIX, IIRC соответствует стандартным требованиям только двух разных указателей, имеющих различный выход для конкретной реализации. –

+0

@MatteoItalia Спасибо. Обновлено. –

+0

Хорошая цитата, но на практике, как может произойти тот факт, что ** неявное литье не происходит ** влияет на значение переданного аргумента (другими словами, как заставить приведение к 'void *" сделать значение ' pi' любой другой)? –

8

Внутреннее представление или размер различных типов указателей не обязательно одинаковые.

Например, на одной системе sizeof(void*) может быть 2, но sizeof(int*) равно 1.

Поскольку printf является переменной аргумент функции, он не может проверить типы входящих параметров. Если вы передадите ему int*, он будет читать неправильное количество байтов, потому что он ожидает void*.

8

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

Кроме того, объекты-указатели разных типов не должны иметь одинаковое представление: C не гарантирует, что sizeof (void *) == sizeof (int *), например. C только гарантирует, что void * имеет то же представление, что и указатели на типы символов.

+0

Я бы не сказал «Кроме того», а скорее «Это потому, что»: если № 2 не было, не было причин для №1. Значение, если все указатели будут выглядеть как друг друга с точки зрения макета памяти, не нужно будет указывать UB для не-'void'' * '. – glglgl

+0

@glglgl Я по-прежнему предпочитаю «помимо этого», потому что в дополнение к C, говорящему, что * Указатели на другие типы не обязательно должны иметь одинаковые требования к представлению или выравниванию * существует определенное правило C для функций 'fprintf', в котором говорится аргумент для' p' должен быть указателем 'void *'. – ouah

+0

Вы правы, но взаимосвязь между ними остается. – glglgl