Почему я не получаю то же значение, что и с %d
, а не с %f
?
void main()
{
int arr;
printf("%f",sizeof(arr));
}
Выход: 2.168831
void main()
{
int arr;
printf("%d",sizeof(arr));
}
вывод: 4
Почему я не получаю то же значение, что и с %d
, а не с %f
?
void main()
{
int arr;
printf("%f",sizeof(arr));
}
Выход: 2.168831
void main()
{
int arr;
printf("%d",sizeof(arr));
}
вывод: 4
sizeof
возвращает size_t
, но printf("%f",...
сообщает printf
, что следующий аргумент имеет тип double
. size_t
имеет другое расположение в памяти, чем double
, поэтому printf
неправильно интерпретирует этот аргумент.
Как указывает Грижеш, правильным спецификатором формата будет %zu
, но если вы действительно хотите использовать %f
printf("%f",(double)sizeof(arr));
должно сработать
%zu
для sizeof (в mcrosoft используется %lu
)
- person Grijesh Chauhan; 12.10.2013
"If a conversion specification is invalid, the behavior is undefined"
из C standard (6.5.2.2 paragraph 6)
ОП сомневается, когда он прокомментировал мне .
- person Grijesh Chauhan; 12.10.2013
Чтобы дать немного больше пояснений, это потому, что printf()
является функцией с переменным числом аргументов, и типы аргументов неизвестны до тех пор, пока функция не запустится и не определит их из строки формата. Это означает, что обычные неявные преобразования не будут выполняться.
Например, если вы делаете что-то вроде:
void myfunc(double d) {
/* Do something with d */
}
int main(void) {
int n = 5;
myfunc(n);
return 0;
}
тогда компилятор знает, что myfunc()
принимает аргумент типа double
, и поэтому может и будет неявно преобразовывать n
из int
в double
перед передачей параметра.
Когда вы делаете:
int main(void) {
double f = 5.5;
printf("%d\n", f); /* WARNING: buggy code */
return 0;
}
компилятор понятия не имеет, какой тип ожидает printf()
, пока не запустится и не поймет %d
в строке формата. Итак, все, что он может сделать, это передать аргумент double
как double
, а когда printf()
запустится и увидит %d
, он интерпретирует его как int
, и все пойдет ужасно неправильно, когда он неправильно интерпретирует битовый шаблон (и, в этом случай, вероятно, размер аргумента, а также отбрасывание его для любых других аргументов, которые идут после него).
Это, среди прочего, причина, по которой эти функции являются одним из тех редких случаев, когда приведение к void *
действительно необходимо в C, поскольку указатели на разные типы объектов могут быть разных размеров, и поскольку %p
ожидает void *
, вы должны передать ему void *
, а не указатель на любой другой тип объекта.
Обратите внимание, однако, что современные компиляторы могут быть умными, и они знают, как работают стандартные функции C, поэтому они могут быть просто проинформированы о стандартном поведении таких функций, как printf()
, чтобы они могли выдавать вам предупреждения о несоответствующих типах аргументов, подобных этому, хотя они на самом деле не исправит их для вас.
Оператор sizeof
возвращает `size_t
Вы должны использовать спецификатор формата %zu
с printf()
Обратите внимание, что size_t
— это unsigned
, размеры signed
могут быть представлены как ssize_t
.
Оба эти типа определены в заголовке stddef.h
§7.21.6.1 p9 стандарта C11 говорит
Если спецификация преобразования недействительна, поведение не определено. Если какой-либо аргумент не является правильным типом для соответствующей спецификации преобразования, поведение не определено.
printf("%f",sizeof(arr));
не определено, второе не использоватьvoid main
использоватьint main
- person Grijesh Chauhan   schedule 12.10.2013%f
ожидаетdouble
, а вы передаетеsize_t
. Это неопределенное поведение. - person   schedule 12.10.2013