Что происходит с переменной float, когда %d используется в printf?

Я пытаюсь выучить C, читая язык программирования C, 2-е издание . У меня есть некоторый опыт программирования, но не с С.

в настоящее время я в Главе 1. У меня есть следующий код:


  float f;
  for (f = 0.0; f <= 3; f += 1.1)
      printf("A: %3f B: %6.2f\n", f, f + 0.15);

он печатает вывод:

A: 0.000000 B:   0.15
A: 1.100000 B:   1.25
A: 2.200000 B:   2.35

выглядит нормально.


теперь я изменяю printf следующим образом:

printf("A: %3d B: %6.2f\n", f, f + 0.15);

новый выход

A:   0 B:   0.00
A: -1610612736 B:   0.00
A: -1610612736 B: -625777476808257557292155887552002761191109083510753486844893290688350183831589633800863219712.00

что здесь происходит? Я ожидал бы, что float для преобразования в int, потому что я использовал %d, но это не так. Кроме того, почему значение B также пошло не так? Что случилось с f здесь?

2 ответов


когда ты позвал:

printf("A: %3d B: %6.2f\n", f, f + 0.15);

C автоматически преобразует float значения double (это стандартное преобразование, выполняемое при вызове функции, которая принимает переменные аргументы, такие как int printf(const char *fmt, ...);). Для аргументации предположим, что sizeof(int) 4 и sizeof(double) - 8 человек (есть исключения, но их мало и далеко между).

вызов, таким образом, нажал указатель на стек, плюс 8-байтовый двойной для f, и другой 8-байтовый двойной для f + 0.15. Когда он обрабатывает строку формата,%d говорит printf() что вы нажали 4-байтовый int в стек после строки формата. Поскольку это не то, что вы сделали, вы вызвали неопределенное поведение; что бы ни случилось дальше, это нормально в соответствии со стандартом C.

однако наиболее вероятная реализация беспечно считывает 4 байта и печатает их, как если бы они были int (она доверяет вам, чтобы сказать ему правду). Затем он натыкается на %6.2f формат; it будет считывать 8 байтов из стека как double. Существует внешний шанс, что это вызовет ошибку памяти для несоосного доступа (для этого потребуется 64-разрядная машина с требованием, что double быть выровненным по 8-байтовой границе, например SPARC), или он будет читать 4 байта из f и 4 байта от f + 0.15, поставив их вместе, чтобы создать некоторые довольно неожиданный double value -- как показывает ваш пример.


Printf будет обрабатывать память, на которую вы указываете, как бы вы ни сказали. Никакого обращения не происходит. Он обрабатывает память, которая представляет float как int. Поскольку они хранятся по-разному, вы получаете то, что по существу является случайным числом.

Если вы хотите вывести свой float как целое число, вы должны сначала бросить его:

printf("A: %3d B: %6.2f\n", (int)f, f + 0.15);