一个printf引发的问题

来源:互联网 发布:贾森威廉姆斯生涯数据 编辑:程序博客网 时间:2024/06/05 22:57

牛客网上的一个题目:

intmain(){
  inta;floatb,c;
  scanf("%2d%3f%4f",&a,&b,&c);
  printf("\na=%d,b=%d,c=%f\n",a,b,c);
}
看起来挺简单的,牵扯的东西比较多。

这是我的思路:

printf函数执行的时候,会先把这三个数字压入栈里,然后再执行打印。压入栈的时候按照数据本身的长度来,首先把c和b压入,并且每一个都是8个字节(printf自动转化为double)。然后再压入a是4个字节。然后再执行打印。打印的时候按照用户指定的格式来出栈。首先打印a,a打印正常。然后又打印4个字节长度的b,在栈里面由于b长度是八个字节,并且b目前是64位的表示方式,数据的后面全是0.(float 变double),电脑是小端存储方式,0存储在距离a近的地方。打印b的时候,打印的4个字节都是0.然后再打印c,c用正常的方式打印,会一下子读取8个字节,正好,读出来的八个字节前面四个字节全是0,自己可以算一下,实在太小了,因此为0.
栈底                                          栈顶
高字节。。。。。。。。。。。低字节
4321     0000      765     0000         98
4字节   4字节    4字节    4字节      4字节
             打印c                 打印b      打印a
附:浮点数(单精度的float和双精度的double)在内存中以二进制的科学计数法表示,表达式为N = 2^E * F;其中E为阶码(采用移位存储),F为尾数。

float和double都由符号位、阶码、尾数三部分组成,float存储时使用4个字节,double存储时使用8个字节。各部分占用位宽如下所示:

             符号位     阶码      尾数     长度

float              1           8         23      32

double          1         11        52       64

举例子:765.0这个浮点数,这文章中需要转换成64位精度,首先将765转换成二进制 1011111101

然后转换成阶码的形式    1.011111101  *   2^(9)

这里的9转换成11位的阶码为  1023+9=(10000001000),如果是32位的float只需要加127

加上符号位为0,再加上后面的尾数(只取小数部分011111101000)最后得到 的数为  4087E800


在VS中如何查看?

首先进入调试,然后单步调试,在调用堆栈的地方右键进入反汇编 ,如图:


esp是栈的指针,在这可以看到减8的操作,就是入栈的操作。dword ptr[esp]就是对应地址的数据

cvtss2sd是将float转化成double类型的,执行完后可以看一下xmm0的数据

结果正是 4087E800


0 0