Странный вывод printf - PullRequest
3 голосов
/ 05 ноября 2011

Я выполнил следующий код

#include <stdio.h>

int main()
{
    printf("%f\n", 9/5);
}

Вывод: 0.000000

почему бы не 1?

, если я напишу printf("%f %f %d %d\n", (float)9/5, 4, sizeof(float), sizeof(int));

тогда вывод 1.800000 0.000000 4 59

почему бы не 1.800000 4 4 4

на моей машине sizeof (float) это 4

Заранее спасибо

Ответы [ 6 ]

12 голосов
/ 05 ноября 2011

Это потому, что ваш спецификатор формата printf не соответствует тому, что вы его передали:

9/5 относится к типу int. Но printf ожидает float.

Так что вам нужно либо привести его к плавающему значению, либо сделать буквальное число плавающим:

printf("%f\n", (float)9/5);
printf("%f\n", 9./5);

Что касается того, почему вы получаете 0.0, это потому, что printf() читает двоичное представление 1 (целое число) и печатает его как float. Что является небольшим денормализованным значением, очень близким к 0.0.

РЕДАКТИРОВАТЬ: Там также что-то происходит с продвижением типа на Varargs.

В функциях vararg float повышается до double. Так что printf() в этом случае действительно ожидает 64-битный параметр, содержащий double. Но вы передали ему только 32-битный операнд, так что он фактически читает лишние 32-битные данные из стека (в данном случае это ноль) - еще более неопределенное поведение.

3 голосов
/ 05 ноября 2011

Давайте посмотрим, что происходит на уровне битов:

  • Вы вычисляете 9/5, оба числа int -> Это оценивается как 1 (снова int)(скажем, 32 бита):

    0000 0000 0000 0000 0000 0000 0000 0001
    
  • Вы указываете его как аргумент printf

  • Вы указываете printf, что нужно получить 32 битаданные из аргументов и распечатайте его как число с плавающей запятой.
  • printf читает то число, которое я написал выше, и печатает его, как если бы оно было закодировано с IEEE 754. Результат почти равен 0.

Вы можете увидеть здесь преобразование:

0000 0000 0000 0000 0000 0000 0000 0001

оценивается как

1.4012984e-45

Почему

printf("%f %f %d %d\n", (float)9/5, 4, sizeof(float), sizeof(int));

не дает ожидаемого результата, причина в том, что аргумент 4 является int, что составляет 4 байта (на вашем компьютере).Из-за продвижения аргумента, %f ожидает double , что составляет 8 байтов.Это та же проблема, что и выше.

0 голосов
/ 05 ноября 2011

(с плавающей точкой) 9/5 использует только 9, а не результат 9/5. Таким образом, операция / не является целочисленной операцией на данном этапе. (float) (9/5) даст результат 1.00000.

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

Например, в 64-битной системе Linux, компилируя с помощью gcc -Wall, я получаю:

pf.c: In function ‘main’:
pf.c:6:2: warning: format ‘%f’ expects argument of type ‘double’, but argument 3 has type ‘int’ [-Wformat]
pf.c:6:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 4 has type ‘long unsigned int’ [-Wformat]
pf.c:6:2: warning: format ‘%d’ expects argument of type ‘int’, but argument 5 has type ‘long unsigned int’ [-Wformat]

Как уже упоминалось выше, вам нужны правильные спецификаторы формата. Использование правильных спецификаторов формата и приведения дает:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv)
{
    printf("%f %f %lu %lu\n",(float)(9/5),(float)4,sizeof(float),sizeof(int));
    return 0;
}

дает:

snits@perelman:~/proj/c=>./pf
1.000000 4.000000 4 4
0 голосов
/ 05 ноября 2011

9/5 - это целое число, но вы пытаетесь напечатать его с "% f".Это источник проблемы.Переключитесь на 9.0 / 5 или "% d", и вы получите правильный ответ.

0 голосов
/ 05 ноября 2011

Если вы создаете с помощью GCC, вы должны включить все предупреждения с помощью -Wall и , внимательно прочитайте их.

Причина, по которой вы получаете "странный" вывод, заключается в том, что вы нарушили предварительные условия printf (передавая аргументы, типы которых не соответствуют спецификации формата), и как только вы это сделали, printf может делать все, что захочет В том числе сбой, печать мусора или таяние вашего процессора.

0 голосов
/ 05 ноября 2011

Использование неверных спецификаторов формата внутри printf - UB.

 printf("%f %f %zu %d\n", (float)9/5, 4.0, sizeof(float), sizeof(int));

дает правильный вывод.

...