快上网专注成都网站设计 成都网站制作 成都网站建设
成都网站建设公司服务热线:028-86922220

网站建设知识

十年网站开发经验 + 多家企业客户 + 靠谱的建站团队

量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决

c语言函数参数入栈 栈的入栈函数名

printf函数参数入栈

这个现象确实存在,但并非在printf()函数中要先执行函数的原因。这可以用下面的代码作试验,证明不是这个原因。

创新互联公司专注于晋中企业网站建设,自适应网站建设,商城建设。晋中网站建设公司,为晋中等地区提供建站服务。全流程定制制作,专业设计,全程项目跟踪,创新互联公司专业和态度为您提供的服务

#include

"stdio.h"//。

int

Add1(int

*p){

return(*p+=1);

}

void

main(void){

int

a=1;

printf("[%d]

[%d]\n",Add1(a),a);

}

这段代码的运行结果是[2]

[1],说明并没有先执行函数Add1()。而如果把printf("[%d]

[%d]\n",Add1(a),a)改为printf("[%d]

[%d]\n",a,Add1(a))则结果是[2]

[2]。这个结果也说明printf()函数确实是从参数列表的右端开始执行的。

那么造成题目中的现象是什么原因呢?这是由C/C++对数组的处理机制造成的。printf()函数在处理数组时只把数组首地址压入栈而并不压入数组下标变量的所有内容(因为没有必要,有首地址就可以输出了)。当printf()函数从参数列表的右端开始一项一项运算压栈到最左端的一个参数后,又从左端的控制符开始按控制符指令一项一项对应弹出。对于其他变量来说,压入的是值,原来计算的结果是什么,弹出的就是什么;而题目中的字符串则不然了,先压入首地址p时,尽管p指向的内容是大小写并存的,但接着被strupr(p)变成全大写了,但压入的首地址还是由strupr(p)返回的同一个地址,弹出来输出时这个地址开始的字串已全是大写字母了……

不知说清楚了没有?供参考……

C语言函数调用栈

程序的执行过程可看作连续的函数调用。当一个函数执行完毕时,程序要回到调用指令的下一条指令(紧接call指令)处继续执行。函数调用过程通常使用堆栈实现,每个用户态进程对应一个调用栈结构(call stack)。编译器使用堆栈传递函数参数、保存返回地址、临时保存寄存器原有值(即函数调用的上下文)以备恢复以及存储本地局部变量。

不同处理器和编译器的堆栈布局、函数调用方法都可能不同,但堆栈的基本概念是一样的。

寄存器是处理器加工数据或运行程序的重要载体,用于存放程序执行中用到的数据和指令。因此函数调用栈的实现与处理器寄存器组密切相关。

AX(AH、AL):累加器。有些指令约定以AX(或AL)为源或目的寄存器。输入/输出指令必须通过AX或AL实现,例如:端口地址为43H的内容读入CPU的指令为INAL,43H或INAX,43H。目的操作数只能是AL/AX,而不能是其他的寄存器。 [5]

BX(BH、BL): 基址寄存器 。BX可用作间接寻址的地址寄存器和 基地址寄存器 ,BH、BL可用作8位通用数据寄存器。 [5]

CX(CH、CL):计数寄存器。CX在循环和串操作中充当计数器,指令执行后CX内容自动修改,因此称为计数寄存器。 [5]

DX(DH、DL):数据寄存器。除用作通用寄存器外,在 I/O指令 中可用作端口 地址寄存器 ,乘除指令中用作辅助累加器。 [5]

2.指针和 变址寄存器

BP( Base Pointer Register):基址指针寄存器。 [5]

SP( Stack Pointer Register): 堆栈指针寄存器 。 [5]

SI( Source Index Register):源变址寄存器。 [5]

DI( Destination Index Register):目的变址寄存器。 [5]

函数调用栈的典型内存布局如下图所示:

图中给出主调函数(caller)和被调函数(callee)的栈帧布局,"m(%ebp)"表示以EBP为基地址、偏移量为m字节的内存空间(中的内容)。该图基于两个假设:第一,函数返回值不是结构体或联合体,否则第一个参数将位于"12(%ebp)" 处;第二,每个参数都是4字节大小(栈的粒度为4字节)。在本文后续章节将就参数的传递和大小问题做进一步的探讨。 此外,函数可以没有参数和局部变量,故图中“Argument(参数)”和“Local Variable(局部变量)”不是函数栈帧结构的必需部分。

其中,主调函数将参数按照调用约定依次入栈(图中为从右到左),然后将指令指针EIP入栈以保存主调函数的返回地址(下一条待执行指令的地址)。进入被调函数时,被调函数将主调函数的帧基指针EBP入栈,并将主调函数的栈顶指针ESP值赋给被调函数的EBP(作为被调函数的栈底),接着改变ESP值来为函数局部变量预留空间。此时被调函数帧基指针指向被调函数的栈底。以该地址为基准,向上(栈底方向)可获取主调函数的返回地址、参数值,向下(栈顶方向)能获取被调函数的局部变量值,而该地址处又存放着上一层主调函数的帧基指针值。本级调用结束后,将EBP指针值赋给ESP,使ESP再次指向被调函数栈底以释放局部变量;再将已压栈的主调函数帧基指针弹出到EBP,并弹出返回地址到EIP。ESP继续上移越过参数,最终回到函数调用前的状态,即恢复原来主调函数的栈帧。如此递归便形成函数调用栈。

EBP指针在当前函数运行过程中(未调用其他函数时)保持不变。在函数调用前,ESP指针指向栈顶地址,也是栈底地址。在函数完成现场保护之类的初始化工作后,ESP会始终指向当前函数栈帧的栈顶,此时,若

c语言函数参数入栈顺序

从右向左;

例如:f(int a, int b, int c)

c先入栈,然后b,其次a;

C语言中函数参数压栈方式为什么是从右到左的

因为有些是不定参数的

这样函数内 在处理的时候 从左到右 会更方便。

根据前面的参数 来确定后面还有多少参数 这样。

要函数内部弹栈从左到右

那么压栈就只能从右到左了。

C语言中函数参数压栈方式为什么是从右到左

栈是先入后出的数据结构.

函数参数从右到左, 那么到函数内部出栈的时候就是从左到右的顺序了.

对于普通函数无区别. 但对于可变参函数, 会根据左侧参数来决定共计有多少参数, 每个类型是什么.

比如 printf scanf这类的.

于是 就设计成从右到左的压栈方式了.

C语言中函数参数为什么是由右往左入栈的

C语言最早设计时最大程度考虑方便与省事(牺牲安全),

函数调用时函数参数个数与类型不进行匹配校验,调用时传入几个参数

可以随便(叫可变参数),如printf。这样为了让被调用函数知道

第一个参数在哪里,C语言中函数参数就采用由右往左入栈的办法,可以方便定位

第一个参数在哪里


当前标题:c语言函数参数入栈 栈的入栈函数名
路径分享:http://6mz.cn/article/doophpj.html

其他资讯