关于C语言中函数调用和参数传递机制的探讨

时间:2010-05-08 15:41:47  来源:第二电脑网  作者:第二电脑网

  第二电脑网导读:友能够从我这篇文章了解函数调用的机制。但是并不是每个人都可以完全读懂这文章,想完全读懂此文,我想必须具备三个条件:  一、对于C语言有一定的了解,最起码有一个整体的初步了解;  二、能够读懂UNIX/LINUX下的AT&T语法的汇编;AT&T汇编与Intel汇编的差别还是挺大的;这个条件可能一些人就不具备了,但是你通过阅读此文相信也能对函数调用机制有一个大概的...
  正文:

关于C语言中函数调用和参数传递机制的探讨

 
函数,相信许多人也知道其重要性;一个文件往往由一个或者多个函数构成的。然而可能许多人还不知道函数调用的一些深层问题,所以我写的这篇文章一来是应
了一个好朋友的要求而写,二来希望一些朋友能够从我这篇文章了解函数调用的机制。但是并不是每个人都可以完全读懂这文章,想完全读懂此文,我想必须具备三
个条件:

  一、对于C语言有一定的了解,最起码有一个整体的初步了解;

  二、能够读懂UNIX/linux下的AT&T语法的汇编;AT&T汇编与Intel汇编的差别还是挺大的;这个条件可能一些人就不具备了,但是你通过阅读此文相信也能对函数调用机制有一个大概的了解;

  三、看到这么长的文章,一定要有耐心,用心看相信应该多少有点帮助;

  好了,不讲废话了,进入主题吧。

一、基础知识框架了解:

  这部分主要讲一些基础的东西,主要是关于堆栈的知识。只有了解了堆栈的基础内容,才可以继续往下读。

1.概念性的知识:

  所谓堆栈,其实也就是程序使用的一种内存元素;它是内存中用来存放一些数据的区域。我曾经写过一篇文章发表在这个论坛上里面也谈到了堆和栈的区别;平常经常说的堆栈,其实也是栈,而不是堆,所以这里也一样。注意这和数据结构说的栈其实还是有区别的,不要混在一起。

2.堆栈的工作方式:
  
  平常我们所说的数据是怎么存放在内存的?是从低地址开始,然后按照数据占用字节大小往高地址逐个存放的。但堆栈就不一样了。堆栈的工作方式是数据插入堆栈区域然后从堆栈区域删除数据。这是概括的说法。具体是这样的:
  
  在UNIX/LINUX
中,堆栈是从高地址向低地址衍生的。这里得说一个重要的东东,那就是堆栈指针ESP。堆栈指针是什么?它永远指向堆栈中的顶部(但如果按照地址值来说却是
底部),是不是对顶部这个词的理解感觉有点模糊?就是说,比如说你压栈,就压进一个4字节的数据元素,那么ESP就向下移动了4个字节,注意这里是向下移
动,所以ESP应该指向了更低的地址,所以说它是指向了底部。你可以把堆栈想象成一个杯子,倒进水了水平线是不是上升了(这里把杯子最底端假设成高地址,
把顶端设为低地址),倒出水了水平线是不是下降了?就和压栈和进栈的道理一样的。如果还没有
理解也没关系,自己画个图仔细比较就可以了。这里让我偷懒一下就不画图了。
  
3.压栈和进栈指令简介:

  压栈指令 :   pushx  source

  其中, 'x'可以是 'w'(表示字), 或者是'l'(表示长字);source可以是数值或者寄存器值或者内存地址;

  出栈指令 :   popx  des

  同样,'x'可以是 'w'(表示字), 或者是'l'(表示长字);des可以是寄存器值或内存值;

  关于最最基础的东西已经讲得差不多了,当然还有其他一些基础东西,留给大家去查资料了,这部分讲的都和本文有密切关系的东西。

二、函数如何通过堆栈来解决问题:

  这部分是对函数如何通过堆栈解决函数调用以及参数传递的理论性理解,相当重要,只有了解之后才可以进行实例的分析,这一大部分同样分成几个小部分:

1.通过堆栈操作实现参数的传递:

 
前面说过,堆栈的基础操作可以是压栈和出栈,而参数的传递就是通过这种方式来实现的。ESP永远指向了堆栈顶部,如果这时候压进一个int型的数据元
素,那么ESP向下移动了4个字节,这时候它还是指向了堆栈的顶部(注意了,顶部的地址比移动前的地址低,不要乱了)。假如把一个int型数据元素出栈,
那么ESP向上移动4个字节,这时候它还是指向了堆栈的顶部,只是现在地址是增加了4个字节。所以,如果一个函数需要传递参数过去那么就得在调用函数之前
先把参数压进栈,然后再调用。关于这点后面我会详细说一下,现在你如果没理解也没关系。

2.函数调用的一般汇编指令:

  函数调用的一般汇编指令都是那么几条,下面我把他们按一般顺序罗列出来:

  #Asm Code
  
  function:
      pushl  %ebp
      movl  %esp, %ebp
      subl  $8, %esp
      #...
      movl  %ebp, %esp
      popl  %ebp
      ret

  下面先简单分析这几句一般汇编指令的意思和目的。

  pushl  %ebp      #这句把寄存器%ebp压栈,目的是什么呢?看下一条指令:

  movl  %esp, %ebp   
#把寄存器%esp的值给了寄存器%ebp;想想前面说到的%esp寄存器是干什么的?用于指向堆栈的顶部,现在通过这条指令,%ebp都是指向了堆栈
的顶部了;所以看看第一条指令,其实就是为了保护原来在%ebp寄存器中的内容#那么这里为什么又要把%esp的值赋给%ebp呢?这里的巧妙就来了。在 《关于C语言中函数调用和参数传递机制的探讨》由第二电脑网原创提供,转载请注明:http://www.002pc.com/master/College/Language/VC/2010-05-08/13932.html

 1/5    1 2 3 4 5 下一页 尾页


关键字:

关于《关于C语言中函数调用和参数传递机制的探讨》文章的评论

站内搜索: 高级搜索

热门搜索: Windows style 系统 tr IP QQ CPU 安装 function 注册 if td