Chinaunix首页 | 论坛 | 博客
  • 博客访问: 389056
  • 博文数量: 61
  • 博客积分: 2525
  • 博客等级: 少校
  • 技术积分: 455
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-24 13:22
文章分类

全部博文(61)

文章存档

2008年(4)

2007年(57)

我的朋友

分类: C/C++

2007-12-16 23:50:22

今天碰到一个我们平常很少涉及到的问题,在这里分析一下,给那些感兴趣的人吧..呵呵~~
C语言中,K&R是c标准前早期的一个c语言版本,相信大家不是很陌生..虽然现在极少用到...毕竟在当时还是做出了极大的贡献,很多unix/linux版本里面都有它的身影...
这里碰到的问题是关于函数调用参数方面的
 

//K&R旧版
int func(p1,p2)
int p1int p2;

{
//..
}
//对应的标准格式
int func(int p1,int p2)
{
//...
}

在说出问题和分析之前,先指出这两种的差别之处:

摘抄出来的:

The parameters are named between the parentheses, and their types are declared beforeopening the left brace; undeclared parameters are taken as int.No parameter list was permitted, so the compiler could not readily check that power was being called correctly. Indeed, since by default power would have been assumed to return an int, the entire declaration might well have been omitted.
The new syntax of function prototypes makes it much easier for a compiler to detect errors in the number of arguments or their types. The old style of declaration and definition still works in ANSI C, at least for a transition period, but we strongly recommend that you use the new form when you have a compiler that supports it.

总之,意思就是说,旧版函数定义中参数的检查是在运行时检查处理,而新版的函数调用是在编译的时候就检查和确定的

问题的提出:两个函数定义AA,BB,函数体内容一样,除了参数定义格式

#include <stdio.h>
long AA(p)
long p;
{
   return (p*10);
}
long BB(long p)
{
   return (p*10);
}
int main()
{
   printf("function AA = %d, BB = %d \n",AA(10.0),BB(10.0));
}

最后编译出来的结果 AA=0,BB=100

反汇编函数AA和BB,其函数体实际内容均相同,唯一不同在于在main函数内调用函数AA和BB的压栈部分,以下是反汇编具体代码

AA和BB一样

0x08048328 <AA+0>: push %ebp
0x08048329 <AA+1>: mov %esp,%ebp
0x0804832b <AA+3>: mov 0x8(%ebp),%edx
0x0804832e <AA+6>: mov %edx,%eax
0x08048330 <AA+8>: shl $0x2,%eax
0x08048333 <AA+11>: add %edx,%eax
0x08048335 <AA+13>: shl %eax
0x08048337 <AA+15>: leave
0x08048338 <AA+16>: ret

调用AA和BB的main函数

0x0804834f <main+0>: push %ebp
0x08048350 <main+1>: mov %esp,%ebp
0x08048352 <main+3>: sub $0x8,%esp
0x08048355 <main+6>: and $0xfffffff0,%esp
0x08048358 <main+9>: mov $0x0,%eax
0x0804835d <main+14>: sub %eax,%esp
0x0804835f <main+16>: sub $0x4,%esp
0x08048362 <main+19>: sub $0x8,%esp
0x08048365 <main+22>: push $0xa             ;压入BB参数0x0a即10
0x08048367 <main+24>: call 0x8048339 <BB>   ;调用BB
0x0804836c <main+29>: add $0xc,%esp
0x0804836f <main+32>: push %eax             ;将BB的结果压栈
0x08048370 <main+33>: push $0x40240000      ;压入AA参数,注意是浮点数
0x08048375 <main+38>: push $0x0             ;所以是两个4字节占64位
0x08048377 <main+40>: call 0x8048328 <AA>   ;调用AA
0x0804837c <main+45>: add $0x8,%esp
0x0804837f <main+48>: push %eax             ;将AA的结果压栈
0x08048380 <main+49>: push $0x804843c
0x08048385 <main+54>: call 0x8048268 <printf>  ;调用printf
0x0804838a <main+59>: add $0x10,%esp
0x0804838d <main+62>: leave
0x0804838e <main+63>: ret

但是在AA函数的调用中,因为隐式转换,仅仅只需要一个long,4字节,所以只是调用了栈顶的一个一个4字节数0x0,(本来压入的是0x40240000和0x0),所以最后得出的结果只能是0.

这就前面所说的K&R调用模式在编译的时候并不确定参数的类型,所以索性直接把数原原本本的压入栈里面了,对于单4字节数据还好,但是到了浮点数就不行了,如果数据进行隐式转换就只用到一部分数据,导致错误.

这里有必要讲讲浮点数在计算机中的表示格式

[摘抄来的]

先说说32 位的 float型.
一个浮点数 X, 在计算机中表示为:
         X = a  *  2e  
 
这里 e 代表指数,  a 代表尾数,   在 计算机内部, 他们都是用二进制表示的. 其中 a 用二进制的科学表示法表示, 由于科学表示法第一位总是1 (0除外) , 所以第一位略去不计.  e 表示的时候, 因为要表示出负数, 所以 要加上127 ,  实际运算的时候要减去 127.

IEEE 规定, 32 位 float型被拆开成以下格式, 左边为高位 :
           0                                 0000 0000                     0000000 00000000 00000000
        最高位,第32位            第 31-23位,共8位                第23-1位            
        符号位                            指数位                                   尾数位
      0为正,1为负               -127~+127                        0~0x 7f ff ff

float 的范围是 -3.40282 * e38 ~ + 3.40282 * e38

一般在人看来是 十进制的数, 要转换成二进制. 十进制转二进制, 大于1 的部分就是除以2 取余, 小于1 的部分乘2 取整.
 比如 8.5  转换成二进制就是 1000.1 , 处理成这一步, 还要用科学表示法表示, 就成了 1.0001 * 23 ,  注意: 由于1.0001 第一个1 要去掉, 所以成了 0001 , 3 需要加上 127 就成了 130 , 二进制就是 10000011 套用上面话就表示为:
     0  10000011 0001000  00000000 00000000
     16 进制 就是:   0x 41 98 00 00 , 一般来说 , intel 系列的 CPU 都使用的是 小尾存放, 就是 高字节放在后面, 刚好要掉过来就是:   0x 00 00 98 41 , 这样就完成了一次浮点数的表示.

注意: 浮点数 0.0  在计算机中表示为 0x 00 00 00 00 .

其余的大家自己分析~~

阅读(2280) | 评论(1) | 转发(0) |
给主人留下些什么吧!~~