Chinaunix首页 | 论坛 | 博客
  • 博客访问: 147542
  • 博文数量: 22
  • 博客积分: 854
  • 博客等级: 军士长
  • 技术积分: 415
  • 用 户 组: 普通用户
  • 注册时间: 2008-05-08 13:44
文章存档

2013年(1)

2012年(5)

2011年(1)

2010年(5)

2009年(2)

2008年(8)

分类: C/C++

2008-09-10 14:53:56

本文档的Copyleft归skyfeces所有, 使用GPL发布, 可以自由拷贝, 转载, 转载时请保持文档的完整性, 严禁用于任何商业用途。
msn: skyfeces@139.com
来源:http://fordme.cublog.cn

昨天跟一个朋友讨论一个问题:
float n1=3.0;
double n2=3.0;
long n3=2000000000;
long n4=1234567890;
printf("%ld %ld %ld %ld\n", n1, n2, n3, n4);

在x86 32位机上执行,输出结果是:0 1074266112 0 1074266112
按照我的理解,float和long在32位机下都占4个字节,即使无法格式化为long进行输出,后面的值也不至于都出问题。

实际里面涉及以下的知识,
1. 把上面的代码反汇编可以看到:
mov    0x80494b4,%eax
mov    %eax,0x18(%esp)
mov    0x80494b0,%eax
mov    %eax,0x14(%esp)
fldl   0x80494a8
fstpl  0xc(%esp)
flds   0x80494a0
fstpl  0x4(%esp)
movl   $0x8048478,(%esp)
call   0x804828c
我先后把这几个变量定义成了局部和全局的进行了测试,这段是用全局的汇编码。
关键是这几句:
fldl   0x80494a8
fstpl  0xc(%esp)
flds   0x80494a0
fstpl  0x4(%esp)
fldl把浮点地址交给浮点运算寄存器,浮点寄存器是64为精度的,然后fstpl再把值取出按照64位入栈,表象就是按照double类型入栈了

。所以虽然内存中单精度浮点数是以4字节存储的,但编译器把它转成了8字节进行处理。
所以最后在栈里的存储就成了
| 00 00 00 00 |<--ESP
| 40 40 00 00 | 
| 00 00 00 00 |
| 40 40 00 00 |
| 49 96 02 d2 |
| 77 35 94 00 |<--EBP

2. printf的处理方式是将输入参数按照字符串进行格式化解析,由于输入的是ld ld ld ld,按照4字节依次进行取值,就得到了上面的结果。

3. float是单精度浮点,遵从IEEE754, S(1)-E(8)-M(23)。3二进制位11,表示为:1.1×2^1 => 指数部分127+1=128-

>10000000,小数部分为1,因此其浮点表示为:
0 10000000 10000000000000000000000,也就是上面1中看到的0x40400000,打印出的十进制就是1074266112。

后来又找来台cavium64位的机器上跑了一下,发现都是正确的,即使按照%d方式输出也没有问题,没法在cavium上反汇编无法确认。
阅读(1800) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~