printf函数如何处理%f规范? [英] How printf function handle %f specification?
问题描述
我有几个程序的输出我不明白:
程序1
#include< stdio.h>
int main(void)
{
int i = 1;
float k = 2;
printf(k is%f \\\
,k);
printf(i is%f \\\
,i);
返回0;
输出在 http://codepad.org/ZoYsP6dc
k是2.000000
i是2.000000
Program 2
现在再举一个例子
#include
int main(void)
{
char i ='a';
int a = 5;
printf(我是%d \\\
,i); //这里%d在int
中输入char类型的值charf(a是%f \ n,a); // hete%f不用类型转换float value
printf(a is%f \\\
,(float)a); //如果我们用%f写(float),那么它工作
return 0;
}
这里输出在 http://codepad.org/XkZVRg64
i是97
a是2.168831
a是5.000000
问题
这是怎么回事?为什么我要显示输出?
您可能在64位x86架构上运行此应用程序。在这个架构中,浮点参数在XMM寄存器中传递,而整数参数在通用寄存器中传递。请参阅 System V AMD64 ABI协议。
因为
%f
需要一个浮点值: printf (我是%f \\\
,i);
打印来自XMM0寄存器的值,恰好是 k
在RSI寄存器中传递,而不是 i
。大会看起来像这样:
movl $ .LC1,%edi#k is%f \\\
movsd .LC0(%rip),%xmm0#float k = 2
call printf
movl $ 1,%esi#int i = 1
movl $ .LC2,%edi#i is %f \\\
call printf#打印xmm0是因为%f,而不是esi
如果您按如下方式重新排列作业:
int i = 1;
printf(i is%f \\\
,i);
float k = 2;
printf(k is%f \\\
,k);
打印:
i是0.000000
k是2.000000
由于XMM0寄存器碰巧值为0。
$ p $ b在32位x86上也是可重现的。在这个平台上 printf()
基本上是铸造 int *
到 double *
然后读取 double
。我们来修改一下这个例子,让我们很容易看到:
int main(){
float k = 2;
int i = -1;
printf(k is%f \\\
,k);
printf(i is%f \\\
,i,i);
$ b $ 64 $输出
k是2.000000
i是2.000000
32位输出:
k是2.000000
i是-nan
也就是说,值为-1的2 int
s看起来像一个 double
0xffffffffffffffff这是一个 NaN
值。
I have a couple of programs whose output I cannot understand:
Program 1
#include <stdio.h>
int main(void)
{
int i=1;
float k=2;
printf("k is %f \n",k);
printf("i is %f \n",i);
return 0;
}
Output is at http://codepad.org/ZoYsP6dc
k is 2.000000
i is 2.000000
Program 2
Now one more example
#include <stdio.h>
int main(void)
{
char i='a';
int a=5;
printf("i is %d \n",i); // here %d type cast char value in int
printf("a is %f \n",a); // hete %f dont typecast float value
printf("a is %f \n",(float)a); // if we write (float) with %f then it works
return 0;
}
Here output is at http://codepad.org/XkZVRg64
i is 97
a is 2.168831
a is 5.000000
Question
What is going on here? Why am I getting the outputs shown?
解决方案 You are probably running this application on a 64-bit x86 architecture. On this architecture floating point arguments are passed in XMM registers, whereas integer arguments get passed in the general purpose registers. See System V AMD64 ABI convention.
Because %f
expects a floating point value:
printf("i is %f \n",i);
prints the value from XMM0 register, which happens to be the value of k
assigned earlier and not i
passed in RSI register. Assembly looks like this:
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
If you reorder the assignments like this:
int i = 1;
printf("i is %f \n",i);
float k = 2;
printf("k is %f \n",k);
It prints:
i is 0.000000
k is 2.000000
Because XMM0 register happens to have value of 0.
[Update]
It is reproducible on a 32-bit x86 as well. On this platform printf()
is basically casting int*
to double*
and then reading that double
. Let's modify the example to make it easy to see:
int main() {
float k = 2;
int i = -1;
printf("k is %f \n",k);
printf("i is %f \n",i,i);
}
64-bit output:
k is 2.000000
i is 2.000000
32-bit output:
k is 2.000000
i is -nan
That is, 2 int
s with value of -1 look like a double
0xffffffffffffffff which is a NaN
value.
这篇关于printf函数如何处理%f规范?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!