printf函数如何处理%f规范? [英] How printf function handle %f specification?

查看:563
本文介绍了printf函数如何处理%f规范?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有几个程序的输出我不明白:

程序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 ints with value of -1 look like a double 0xffffffffffffffff which is a NaN value.

这篇关于printf函数如何处理%f规范?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆