Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1838874
  • 博文数量: 343
  • 博客积分: 10342
  • 博客等级: 上将
  • 技术积分: 2892
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-15 12:34
个人简介

你必须非常努力,才能看起来毫不费力!

文章存档

2012年(3)

2011年(5)

2010年(2)

2009年(40)

2008年(293)

分类:

2008-10-06 12:58:18


2004-10-24

作  者:杨延庆
E-mail:


    
昨天忽然想起来函数压栈顺序的问题,就跟舍友讨论了一下,结果发现在不同的编译器下面出现的结果竟然不一样!于是做了如下分析:

【源程序】

#include <stdio.h>


void
print(int a, int b, int c)
{
    printf("%d\t%d\t%d\n", a, b, c);
}

int main(void)

{

    int p = 0;

    print(p++, ++p, p++);
     return0;

}

【调用分析】
    其实大家应该都知道这个顺序了,我简单粗略的提一下吧。
    C
C++ 编译器进行函数调用的时候参数压栈的顺序时从右向左的。拿上面的程序来说,首先压栈的参数是最后一个“p++”,压栈的值应该是0,此时 p=1;然后压栈参数的是中间的“++p”,压栈的值是2,此时 p=2;最后压栈的是第一个“p++”,压栈的值应该是 2,此时p=3
    
那么,输出结果就应该是“2 2 0”。

【存在问题】
    
TcTc3GCC 下编译通过,运行结果“2 2 0”;
    
VC.net 下编译通过,运行结果“2 3 0”;

【问题分析】
 1Tc3下从压栈到函数调用阶段的汇编代码:(使用方法 tcc -S filename.cpp

   ;    

   ;     {

   ;             int p = 0;

   ;    

       xor        si,si                ; si 清零,即 p=0

   ;    

   ;     print(p++, ++p, p++);

   ;    

       ;将最后一个参数压栈,先压栈,后加1
       mov        ax,si    ;ax=0

       inc        si

       push        ax

       ;将中间的参数压栈,先加1,后压栈
       inc        si

       mov        ax,si    ;ax=2

       push        ax

       ;将第一个参数压栈,先压栈,后加1
       mov        ax,si    ;ax=2

       inc        si

       push        ax

       ;调用 print 函数
       call        near ptr @print$qiii

 

    至此,在 Tc Tc3 下的分析工作完成,结果是“2 2 0”的原因也就很清楚了。

    2Vc.net下从压栈到函数调用阶段的汇编代码:
;
;int p = 0;
;
00411B3E mov dword ptr [p],0;
赋初值 0
;
;print(p++, ++p,p++);
;
;
操作第三个参数
00411B45 moveax,dword ptr [p];eax= 0
p=0
00411B48 mov dword ptr [ebp-0D0h],eax;
存放最第三个参数值
00411B4E mov ecx,dword ptr[p];ecx = 0
00411B51 addecx,1;ecx = 1
00411B54mov dword ptr [p],ecx;p =1
;
操作第二个参数
00411B57 movedx,dword ptr [p];edx = 1
00411B5Aadd edx,1;edx =2
00411B5D mov dword ptr [p],edx;p = 2
00411B60 mov eax,dword ptr[p];eax = 2
00411B63 movdword ptr [ebp-0D4h],eax;
存放第二个参数值
;
操作第一个参数
00411B69 mov ecx,dword ptr[p];ecx = 2
00411B6C addecx,1;ecx = 3
00411B6Fmov dword ptr [p],ecx;p =3
;
开始压栈
00411B72 mov edx,dword ptr [ebp-0D0h];
第三个参数压栈,值为 0
00411B78 push edx
00411B79mov eax,dword ptr [p];
第二个参数压栈,值为3
00411B7C push eax
00411B7D mov ecx,dword ptr[ebp-0D4h];
第一个参数压栈,值为 2
00411B83 pushecx
;
调用 print 函数
00411B84 call print(41100Fh)
00411B89 add esp,0Ch
   
    
至此,在 Vc.net 下的分析工作完成,结果是“2 3 0”的原因是压栈的顺序不是标准 C 语言中压栈的顺序,或者说根本就不是顺序,至于为什么这样我也不清楚,如果 .Net 的开发人员注意到了这个问题的话回个贴吧(痴人说梦^_^)。

【建议】
    
为了你的程序的通用性,不要写那些模棱两可的程序,尽管有很多考试都考这些,我个人不认为把程序写成这样是高手。


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