Возможно, вы запускаете это приложение на 64-битной архитектуре x86.В этой архитектуре аргументы с плавающей запятой передаются в регистрах XMM, тогда как целочисленные аргументы передаются в регистрах общего назначения.См. Система V Соглашение AMD64 ABI .
Поскольку %f
ожидает значение с плавающей запятой:
printf("i is %f \n",i);
печатает значение из регистра XMM0, который являетсязначение k
присвоено ранее, а не i
передано в регистр RSI.Сборка выглядит следующим образом:
movl $.LC1, %edi # "k is %f \n"
movsd .LC0(%rip), %xmm0 # float k = 2
call printf
movl $1, %esi # int i = 1
movl $.LC2, %edi # "i is %f \n"
call printf # prints xmm0 because of %f, not esi
Если переупорядочить назначения следующим образом:
int i = 1;
printf("i is %f \n",i);
float k = 2;
printf("k is %f \n",k);
Она печатает:
i is 0.000000
k is 2.000000
Поскольку регистр XMM0 имеет значение0.
[Update] Воспроизводится также на 32-битном x86.На этой платформе printf()
в основном приводит int*
к double*
, а затем читает double
.Давайте изменим пример, чтобы было легче увидеть:
int main() {
float k = 2;
int i = -1;
printf("k is %f \n",k);
printf("i is %f \n",i,i);
}
64-битный вывод:
k is 2.000000
i is 2.000000
32-битный вывод:
k is 2.000000
i is -nan
То есть, 2 int
s со значением -1 выглядят как double
0xffffffffffffffff, что является значением NaN
.