Повторите это для себя в течение двух недель один раз перед сном:
printf небезопасен. printf небезопасен. printf небезопасен.
Функция будет работать, только если вы передадите ей аргумент того типа, который вы обещаете. Все остальное - неопределенное поведение. Вы обещаете double
(через %f
), но предоставляете int
(тип литерала 7
), так что это неопределенное поведение. Позор вам.
(я однажды углубился в подробности , чтобы объяснить фактический результат, если вам интересно.)
Обновление: Поскольку вас интересует объяснение этого конкретного поведения, вот (соответствующая) сборка для этого кода на моем x86 / GCC4.6.2 / -O3:
Первые разделы данных:
.LC0:
.long 1921946325
.long 1076013872 // 0x 4022AB30 728E92D5 is the binary rep of 9.334354
.LC1:
.string "%.2f\n"
.LC2:
.string "%.5f\n"
.LC3:
.string "%03d\n"
Теперь код:
fldl .LC0 // load number into fp register
fstpl 4(%esp) // put 64-bit double on the stack
movl $.LC1, (%esp) // first argument (format string)
call printf // call printf
movl $7, 4(%esp) // put integer VA (7) onto stack
movl $.LC2, (%esp) // first argument (format string)
call printf // call printf
movl $9, 4(%esp) // put integer VA (9) onto stack
movl $.LC3, (%esp) // first argument (format string)
call printf // call printf
Причина, по которой вы видите то, что вы видите, проста сейчас. Давайте на минутку переключимся на полный 17-значный вывод:
printf("%.17f\n", 9.334354);
printf("%.17f\n", 7);
Получаем:
9.33435399999999937
9.33435058593751243
Теперь давайте заменим целое число на «правильный» двоичный компонент:
printf("%.17f\n", 9.334354);
printf("%.17f\n", 1921946325);
И вуаля:
9.33435399999999937
9.33435399999999937
В результате double
занимает 8 байтов в стеке со значением 0x4022AB30728E92D5
. Целое число занимает только 4 байта, и, как это бывает, наименее значимые четыре байта перезаписываются, поэтому значение с плавающей запятой остается почти таким же. Если вы перезаписываете четыре байта теми же байтами, которые встречаются в исходном плавающем значении, то вы получите точно такой же результат.
Могу добавить, что это просто удача, что старшие четыре байта остаются нетронутыми. При других обстоятельствах они могли быть перезаписаны чем-то другим. Короче говоря, "неопределенное поведение".