Каково поведение printf при печати int как float? - PullRequest
1 голос
/ 20 ноября 2011

Я использую dev cpp на windows7 для компиляции моего кода.

int d = 0x12;
char* e = (char*)&d;
printf("%d %d\n", sizeof (int), sizeof (float));
printf("%p %p\n", &d, (float*)&d);
printf("%p %p %p %p %p\n", &d, &e[0], &e[1], &e[2], &e[3]);
printf(" %d | %x | %#1x | %#1x | %#1x |%p\n", d,  e[0], e[1], e[2], e[3], &e[0]);
getchar();

4 4 
0028FF40 0028FF40
0028FF40 0028FF40 0028FF41 0028FF42 0028FF43  
18 | 12 | 0 | 0 | 0 |0028FF40

Вы видите, что, если я использую% d для печати d, он печатает 4 байта e нормально. Но если я использую% f, как показано ниже, он показывает нули в том месте, где должен быть напечатан первый байт e. Кто-нибудь может помочь с тем, почему это происходит? Почему содержание e должно зависеть от того, как отформатировано d?

int d = 0x12;
char* e = (char*)&d;
printf("%d %d\n", sizeof (int), sizeof (float));
printf("%p %p\n", &d, (float*)&d);
printf("%p %p %p %p %p\n", &d, &e[0], &e[1], &e[2], &e[3]);
printf(" %f | %x | %#1x | %#1x | %#1x |%p\n", d,  e[0], e[1], e[2], e[3], &e[0]);
getchar();

Вывод:

4 4
0028FF40 0028FF40
0028FF40 0028FF40 0028FF41 0028FF42 0028FF43
 0.000000 | 0 | 0 | 0 | 0x28ff40 |76869F1D

Ответы [ 3 ]

8 голосов
/ 20 ноября 2011

Неопределенное поведение.

На практике то, что вы видите, вероятно, связано с тем, что %f заставляет printf извлечь double из списка аргументов, который составляет 8 байт *.Но размер d составляет всего 4 байта, поэтому теперь все выровнено неправильно.

Помните, что printf - это функция с переменным числом символов, что означает, что она полностью безопасна для типов;printf должен извлекать необработанные байты из стека без помощи компилятора.От вас полностью зависит, чтобы аргументы точно соответствовали строке формата.


* Возможно.
2 голосов
/ 20 ноября 2011

Вы попали под автоматическое продвижение типов.

Похоже, вы предполагаете, что поскольку sizeof (int) == sizeof (float), вы можете передавать d как float или int взаимозаменяемо. Но дело в том, что в Си вы не можете пропустить поплавок.

В C, когда вы используете в выражении символ или шорт, оно автоматически преобразуется в int. Точно так же, когда вы используете float в выражении, оно автоматически конвертируется в double.

Итак, когда вы выполняете printf ("% f", d), компилятор помещает в стек целое число, то есть четыре байта, перед выполнением вызова функции. Затем в функции printf () видит «% f» и вытягивает из стека восемь байтов. Четыре байта, из которых ваше «д», а остальные четыре - это то, что случилось там. В вашем примере e [0] и e [1].

Если вы хотите вывести «d» в виде числа с плавающей точкой, вам нужно явно привести его или присвоить переменной с плавающей точкой. В любом случае компилятор преобразует его в double перед вызовом printf (). (Примечание: как бы странно это не звучало, «% f» используется для печати двойных, а не плавающих чисел. Вы не можете печатать плавающие числа. Вы можете читать числа с плавающей запятой или двойные числа, используя «% f» и «% lf», в scanf (), но в printf () "% f" печатает вдвое.)

1 голос
/ 20 ноября 2011

Да, вы вытаскиваете 8 байтов из стека, четыре из которых 0x00000012, остальные зависят от компилятора (возможно, адрес возврата, который был помещен в стек при создании кадра стека для printf).

...