C语言函数调用的传参方法总结,Caller分配内存,Called填充内存
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言函数调用的传参方法总结,Caller分配内存,Called填充内存相关的知识,希望对你有一定的参考价值。
参考技术A void called(int v) v=2;void caller() int v=1; called(v);
这种方式,called并不能改变caller里的v的值,因为called和caller的v分别是两个内存单元,因此只能单向的从caller到called传值,而不能从called到caller返回值。
void called(int *pv) *pv=2;
void caller() int v=1; called(&v);
这种方式,called能改变caller的值,因为值的内存由caller分配(int v=1;),而called能通过其指针改变这个内存的内容。
void called(int **ppv) *ppv=malloc(sizeof(int));
void caller() int *pv=NULL; called(&pv);
这种方式,内存单元是由called分配在heap上的,想返回其地址给caller,因此caller需要提供一个地址的内存(int *pv=NULL;), 然后交由called去改变这个单元的值(called(&pv))。需要注意的是,这个内存不能是在called的stack中,因为一旦called结束,栈中内存都会被销毁,其值和地址都将无效,因而只能返回在heap中的值和地址。
总之就是记住一个宗旨,如果想通过参数来获得返回值,需要在caller中为该返回值分配内存单元,然后将这个内存单元的地址传递给called函数,called函数通过改变这个地址所指向的内存值来返回所需。
C语言函数调用完整过程
C语言函数调用详细过程
函数调用是步骤如下:
- 按照调用约定传参
- 调用约定是调用方(Caller)和被调方(Callee)之间按相关标准
对函数的某些行为做出是商议,其中包括下面内容:
传参顺序:是从左往右传还是从右往左
传参方式:是用寄存器传还是使用内存传
平栈方式:是调用方平栈还是被调方平栈
返回值的传递方式:是用寄存器传还是使用内存传 什么是堆桟?
一个程序运行的时候,它的进程的地址空间一般可以分为四块:
代码区,数据区,堆,栈,每块功能如下:区域 功能 代码区 存放函数被编译后的二进制可执行代码 数据区 只读区:存放常量,例如:常量字符串,const修饰的全局变量等
可读写区:存放全局变量和静态变量堆 除去其他三个区域,剩下的都是堆,不连续 栈 存放函数运行时所需的参数,寄存器环境,返回值,局部变量 以下面代码为例:
函数参数参数传递:int TestFunction(char szBuff[],int nSize) for (int iIndex = 0; iIndex < nSize; iIndex++) szBuff[iIndex] = 'x'; return 3; int main() char szBuff[32] = "sfjdlskfjl" ; int nRet = TestFunction(szBuff, 32); return 0;
从上图中可以看出函数参数入栈 - 调用约定是调用方(Caller)和被调方(Callee)之间按相关标准
- 保存返回地址(紧挨着被调用函数的下一行可执行代码的内存地址)
从上图中可以看出函数调用完成后,紧挨着的第一条指令为:
00EB175B add esp,8
所以,参数传递完成后就是返回值入栈:
- 程序流程转移到被调用函数地址处
- 保存调用方栈底
- 切换到当前函数(被调用函数)的栈底
调用方栈底保存完成后,当前的栈顶(ESP记录的地址)就成为被调用函数的栈底
- 为局部变量分配空间
这里程序为调试版本,所以为局部变量分配的空间比较大,在Release版本中
会根据局部变量实际所需空间来分配大小 - 保存寄存器环境
这里一共保存了3个寄存器,共12字节,在Release版本下,只保存两个
在Debug版程序中(有/Zi(带有调试信息)和/Od(禁止优化)编译命令),除了为
局部变量分配较大的内存空间外,还会将分配的局部变量空间全部置为0xCC:
这种填充方式比较直观,能够让我们在调试时直观的观察到是否发生越界等错误
- 开始执行函数体代码
此时当前函数的栈的内存布局如下:
- 恢复寄存器环境
- 释放分配的局部变量空间
只是将当前的栈底指针(EBP)的值赋值给栈顶指针(ESP)就完成了:
- 恢复调用方栈底
- 平栈或者返回
- 如果是_fastcall,_stdcall调用约定,那么被调用函数平栈后,取出返回地址
函数流程转移到调用方 - 其他调用约定则是直接取出保存的返回地址,函数流程返回到调用方,又调用方
平栈
- 如果是_fastcall,_stdcall调用约定,那么被调用函数平栈后,取出返回地址
以上是关于C语言函数调用的传参方法总结,Caller分配内存,Called填充内存的主要内容,如果未能解决你的问题,请参考以下文章