Зависит ли printf () от порядка спецификаторов формата? - PullRequest
4 голосов
/ 01 августа 2010
#include<stdio.h>
main()
{
    float x=2;
    float y=4;
    printf("\n%d\n%f",x/y,x/y);
    printf("\n%f\n%d",x/y,x/y);
}

Вывод:

0 
0.000000
0.500000 
0

скомпилировано с gcc 4.4.3 Программа вышла с кодом ошибки 12

Ответы [ 6 ]

15 голосов
/ 02 августа 2010

Как отмечалось в других ответах, это происходит из-за несоответствия между строкой формата и типом аргумента.

Я предполагаю, что вы используете x86 здесь (на основе наблюдаемых результатов).

Аргументы передаются в стек, а x/y, хотя и имеет тип float, будет передан как double в функцию varargs (из-за правил типа «повышение»).

int - это 32-разрядное значение, а double - это 64-разрядное значение.

В обоих случаях вы передаете x/y (= 0,5) дважды.Представление этого значения в виде 64-битного double равно 0x3fe0000000000000.Как пара 32-битных слов, она сохраняется как 0x00000000 (младшие 32-битные), за которыми следует 0x3fe00000 (старшие 32-битные).Таким образом, аргументы в стеке, как видно из printf(), выглядят так:

0x3fe00000
0x00000000
0x3fe00000
0x00000000  <-- stack pointer

В первом из ваших двух случаев %d вызывает первое 32-битное значение, 0x00000000, чтобы выскочить и распечатать.%f выводит следующие два 32-битных значения: 0x3fe00000 (младшие 32-битные 64-битные double), затем следует 0x00000000 (наиболее значимое).Результирующее 64-битное значение 0x000000003fe00000, интерпретируемое как double, является очень небольшим числом.(Если вы измените %f в строке формата на %g, вы увидите, что это почти 0, но не совсем).

Во втором случае %f правильно выводит первое double, и %d выдает 0x00000000 половину второй double, так что, похоже, работает.

7 голосов
/ 01 августа 2010

Когда вы говорите %d в строке формата printf, вы должны передать значение int в качестве соответствующего аргумента. В противном случае поведение не определено , что означает, что ваш компьютер может зависнуть или посторонние могут постучаться в вашу дверь. Аналогично для %f и double.

4 голосов
/ 01 августа 2010

Да.Аргументы читаются из списка vararg в printf в том же порядке, в котором читаются спецификаторы формата.

Оба оператора printf недопустимы, поскольку вы используете спецификатор формата, ожидающий int, но вы даетеэто float double.

3 голосов
/ 01 августа 2010

То, что вы делаете, - это поведение беззастенчивое.То, что вы видите, случайно;printf может написать что угодно.

Вы должны соответствовать точному типу при предоставлении printf аргументов.Например, вы можете разыграть:

printf("\n%d\n%f", (int)(x/y), x/y);
printf("\n%f\n%d", x/y, (int)(x/y));
2 голосов
/ 01 августа 2010

Этот результат неудивителен, в первом% d вы прошли двойное, где ожидалось целое число.

0 голосов
/ 02 августа 2010

http://en.wikipedia.org/wiki/Format_string_attack

Что-то связано с моим вопросом. Поддерживает ответ Матфея.

...