读书人

一道C语言题目解决思路

发布时间: 2012-03-24 14:00:46 作者: rapoo

一道C语言题目
#include<stdio.h>
int main()
{
float x,y;
x=5;
y=3;
printf("x=%d y=%d\n",x,y);
return 0;
}

这个程序运行的结果是x=0 y=1075052544
我一直以为是随机的,不过好像不是这样,应该和存储结构有关,不知哪一位能够解释一下
如果把 float 改成 double 又是怎么样的呢

[解决办法]
换成double的话,8个字节,后面的0更多了
不过不明白的是为什么这样算下来结果不对,即:

float格式的5存储为:0 10000001 01000000000000000000000
float格式的3存储为: 0 10000000 10000000000000000000000
转换成4字节的int值结果和输出不对。。
[解决办法]
以下分析基于PC,Windows XP SP2,Visual C++ 6.0。

先看看汇编码:

6: x = 5;
0040E9C8 C7 45 FC 00 00 A0 40 mov dword ptr [ebp-4],40A00000h
7: y = 3;
0040E9CF C7 45 F8 00 00 40 40 mov dword ptr [ebp-8],40400000h
8: printf("x = %d, y = %d\n", x, y);
0040E9D6 D9 45 F8 fld dword ptr [ebp-8]
0040E9D9 83 EC 08 sub esp,8
0040E9DC DD 1C 24 fstp qword ptr [esp]
0040E9DF D9 45 FC fld dword ptr [ebp-4]
0040E9E2 83 EC 08 sub esp,8
0040E9E5 DD 1C 24 fstp qword ptr [esp]
0040E9E8 68 1C 30 42 00 push offset string "x = %d, y = %d\n" (0042301c)
0040E9ED E8 8E 26 FF FF call printf (00401080)

注意40A00000H和40400000H,它们是单精度的5.0和3.0。
(可以参考http://www.psc.edu/general/software/packages/ieee/ieee.html)

在第一个fstp指令,0012FF24处(我的机器上esp-8后的地址)被置成4008000000000000,注意,这已经是双精度的3.0了。
第二个fstp指令,0012FF1C处被置成4014000000000000,这是双精度的5.0。
上面两个fstp可以看成是函数调用前的压栈,先压的y,后压的x。

call printf的时候,从0012FF1C开始取x,y的值,但由于传递的是%d,所以只要取4byte就好,x取得00000000,y取得40140000。
这分别就是打印出来的0和1075052544。

以上是个人看法,供参考。

[解决办法]
这个原因其实不用看汇编
这个问题出现和动态参数列表有关。由于是动态参数类别,无论语言和代码都无法决定后续的参数的类型是什么的。在赋值给va_list之后,实际上函数是通过一个无类型或者任意类型的指针而不是对象自己的实际指针类型来处理的

当printf格式化字符串时,他读到%d,就以为这是一个int型的数据,语法上的效果等价于把那个浮点数做如下转换*(int*)&x :注意,这里不是隐式或者显式类型转换,而是仅仅纯粹的内存映射。这样实际上内存布局是float的变量被当作int来处理,由于float的内存布局和int完全不一样,导致输出的结果是不可预期的

因此对于任何动态参数列表的情况,你应该对参数做显式类型转换而不是依赖于隐式类型转换,这式因为隐式类型转换实际上根本不会做,printf只会“以为”他是个整型数,而不会以为他是浮点数再做转换。
[解决办法]
我来简化一下,
float 类型占用4个字节和int 类型相同,因此x=5;y=3;以后
float格式的5存储为:0 10000001 01000000000000000000000
float格式的3存储为: 0 10000000 10000000000000000000000
但是在计算机内浮点运算都是按照double计算的,因此printf("x=%d y=%d\n",x,y);需要调用x,y的值时候先转换成double入栈,然后由于传递的是%d,所以只要取4byte就好,这样就出现了楼主的结果。

读书人网 >C++

热点推荐