函数的返回值,16位/32位

同事的一段代码里出现的异常,内存访问错误。遂一起排查。使用的是VC6.0,系统是Win2K。

主调函数func1,传进一个数组的首地址。用数组的下标方式访问,下标是一个子函数func2的返回值。异常出现在这里。一开始怀疑传进来的地址有问题,跟踪下来发现是对的。我怀疑func2的返回值,但看到这个函数很简单,就一句返回一个结构的WORD成员,好象不应该有错。

func2有一个参数,是一个结构指针lp,函数体是return lp->val。函数声明返回WORD类型,结构的成员val也是WORD类型。

在出事地前加了个printf("%x/n",func2(p)),打印func2的返回值。结果说明了出错原因,打印值是1520000。很明显,func2返回了一个DWORD值。访问数组越界,所以异常。

为什么会这样呢?为什么函数返回类型是WORD,使用时却得到一个DWORD值呢?

做了一个尝试,如果把返回值赋给一个WORD类型的局部变量,得到的值是对的;如果加上类型转换(WORD)func2(p)也是对的。

分别看一下这三种情况(一错二对)的汇编码,可以发现,正确的情况,在func1中使用func2的返回值前有一句:

0040B7F2   and         eax,0FFFFh   //清高16位。

因为在调用func2时,结构指针参数的传递用了32位的eax。func2的汇编码中可以看到,需返回的WORD值放入了16位的ax。所以在func1使用前清高16位,使用的仍然是eax,但值是所需的正确值。

而错误的情况,即不加转换的直接使用,没有这么一句清高位。赋值的时候也没有使用movzx零扩展指令,直接用mov到eax。

0040B7E6   mov         edx,dword ptr [ebp-4]
0040B7E9   push        edx
0040B7EA   call        @ILT+5(_func) (0040100a)
0040B7EF   add         esp,4
0040B7F2   and         eax,0FFFFh     //出错的代码没这句。
0040B7F7   push        eax
0040B7F8   push        offset string "a = %d/n" (00420f74)
0040B7FD   call        printf (00401090)
0040B802   add         esp,8

怀疑是编译器的bug。于是做一个实验。新建一个project,模拟了这个func1和func2。结果的正确的。即使是不加转换的直接使用汇编码里也有清高位,返回的值不会受干扰。更加疑惑。

继续实验。怀疑实际的那个结构有问题。把实际project中的结构移植到实验project中。却也是正确的。

怀疑project的设置有问题。把实验中的结构和函数移植到实际project中,又是正确的。郁闷。

改变此成员在结构中的定义位置,怀疑没有对齐,虽然这不应该是程序员关心的,但也没有发现区别。改变此成员的类型(DWORD,BYTE),都没有找出问题所在。至此,技穷。

希望能找到问题的根源。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值