我们专注攀枝花网站设计 攀枝花网站制作 攀枝花网站建设
成都网站建设公司服务热线:400-028-6601

网站建设知识

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

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

c语言函数调用栈的变化 c语言 函数调用 堆栈

C语言 入栈顺序为什么函数入栈顺序从右往左

C语言函数参数入栈顺序从右到左是为了方便可变参数函数。

创新互联公司专业为企业提供百色网站建设、百色做网站、百色网站设计、百色网站制作等企业网站建设、网页设计与制作、百色企业网站模板建站服务,十多年百色做网站经验,不只是建网站,更提供有价值的思路和整体网络服务。

一、在函数调用时,函数参数的传递,在C语言中是通过栈数据结构实现的。

在调用函数时,先根据调用函数使用的参数,自右向左依次压入栈中,然后调用函数,在函数开始执行时,将参数再依次弹栈。根据栈数据结构先进后出的特点,在函数中弹栈的顺序就是从左向右的。

二、对于参数固定的函数,无论是从左向右还是从右向左,都没什么区别,最终都是所有参数全部传递。

三、对于可变参数,比如printf,会在第一个参数格式字符串中,指明后续有几个参数,各自是什么类型的。于是在函数中,参数格式字符串必须第一个弹栈,否则无法获取参数类型,也就无法获知后续参数占几个字节,导致无法正确获知参数。

四、理论上来说,如果从左向右压栈,可变参数标记格式字符串的参数放在最后,那么也是可以的。 不过最早设计C语言的人采用了这种方式,后续也就延续下来了。

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语言),高手速来!!

/*程序错误太多*/ #include"stdio.h"

#include"stdlib.h"

#include"time.h"

#include"malloc.h"

#define

STACK_INIT_SIZE

10

//栈容量 typedef

struct

SqStack

{

int

top;

//栈顶当前指针

int

*base;

//栈空间数组

}SqStack; void

InitStack(SqStack

S);

//构造空栈S

int

Push(SqStack

S,int

e);

//入栈(栈地址,入栈数据)

返回0对,-1错

int

Pop(SqStack

S);

//出栈

(栈地址)返回栈顶数据

int

StackLength(SqStack

S);

//返回站的元素个数,即求栈长

void

Print_S(SqStack

S);

//显示栈内数据 int

main()

{

SqStack

S;

int

i=0;

int

a,e;

InitStack(S);

srand((unsigned)time(NULL));

//srand((unsigned)time(NULL))以time函数值(当前时间)作为种子

printf("随机填充5个元素为:

");

while(

i5)

{

a

=

rand()%100;

printf("%d

",

a);

Push(S,a);

i++;

}

Print_S(S);

printf("请输入要插入栈顶的元素:");

scanf("%d",e);

Push(S,e);

Print_S(S);

printf("再弹出的栈顶元素为:%d

\n",Pop(S));

printf("栈的长度为:%d

\n",StackLength(S));

Print_S(S);

return

0;

} void

InitStack(SqStack

S)

//构造空栈S

{

S.base

=

(int

*)malloc(STACK_INIT_SIZE

*

sizeof(int));

//分配组数空间,长度STACK_INIT_SIZE

if

(S.base==NULL)

{

printf("内存分配失败!\n");

return;

}

S.top=-1;

} int

Push(SqStack

S,int

e)

{

if(S.top=STACK_INIT_SIZE)

{

printf("栈空间已满,入栈失败!\n");

return

-1;

}

else

{

S.base[++S.top]=e;

return

0;

}

} int

Pop(SqStack

S)

//返回栈顶数据

{

if

(S.top=0)

//栈内有数据

{

return

S.base[S.top--];

}

else

{

printf("空栈,无数据弹出!\n");

return

-1;

}

} int

StackLength(SqStack

S)

{

return

S.top+1;

} void

Print_S(SqStack

S)

{

printf("\n出栈显示:");

if(S.top

==

-1)

printf("栈内无数据!\n");

else

{

while(S.top=0

)

printf("%d

",Pop(S));

putchar('\n');

}

}

C语言中,函数调用是通过栈实现的,怎样理解这句话?

因为函数调用的时候,就要将关键的寄存器的值存入堆栈中,等到执行完之后又从堆栈中取出数据

,计算机底层,有cs和ip的指令指针,指向哪里就执行哪里的指令,但是函数调用会人为的把cs和ip改变, 从而改变了指令执行的位置,自然去执行调用的函数了,但是此时,还是要将关键的寄存器存入堆栈,比如cs,等到调用玩之后,就又从堆栈中取出关键的寄存器的值,cs,ip还有别的一些

尤其是递归函数

c语言:函数调用时,栈的问题——(有请高手高手高高手)

必须出栈!

aa 和 bb 和c 都是函数内部的局部变量,函数返回后就被释放,也就是在栈中没有了,返回后就剩下图中main()函数所对应的栈结构.

栈只能够通过出栈来减少栈中数据的个数,从反面来讲,如果不出栈,funcA()函数返回后,栈指针还是指向c那,这肯定是不对的,因为函数返回后栈指针就得指向man()的栈结构了。


分享文章:c语言函数调用栈的变化 c语言 函数调用 堆栈
URL地址:http://shouzuofang.com/article/hppdgi.html

其他资讯