十年网站开发经验 + 多家企业客户 + 靠谱的建站团队
量身定制 + 运营维护+专业推广+无忧售后,网站问题一站解决
栈是先入后出的数据结构.
专注于为中小企业提供成都网站制作、成都网站设计服务,电脑端+手机端+微信端的三站合一,更高效的管理,为中小企业神池免费做网站提供优质的服务。我们立足成都,凝聚了一批互联网行业人才,有力地推动了上1000+企业的稳健成长,帮助中小企业通过网站建设实现规模扩充和转变。
函数参数从右到左, 那么到函数内部出栈的时候就是从左到右的顺序了.
对于普通函数无区别. 但对于可变参函数, 会根据左侧参数来决定共计有多少参数, 每个类型是什么.
比如 printf scanf这类的.
于是 就设计成从右到左的压栈方式了.
方法很简单:你讲两个栈都传进去,类似于 : int pus(SeqStack1 *s, DataType* x1, SeqStack2 *s, DataType* x2)(SeqStack1是你的第一个栈,SeqStack2是第二个栈,DataType是你需要传进去的数据的类型),然后在这个函数里面先判断x1 ,x2是否为空,如果为空,则他对应的那个栈不需要压栈,如果不为空,则执行相应的压栈操作。
不明白继续追问!
基本正确,补充一点,参数一般是往寄存器里面放,放不下的情况下,才压栈。
什么是堆和栈?
一个由c/C++编译的程序占用的内存分为以下几个部分
1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。其操作方式类似于数据结构中的栈。
2、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表,呵呵。
3、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。 - 程序结束后有系统释放
4、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放
5、程序代码区—存放函数体的二进制代码。
函数压栈是怎么回事?
函数压栈的本质是参数传递
这又跟汇编语言连系起来了.汇编语言的过程即proc可以理解成函数
比如一个最简单的计算两数之和函数
如果用汇编来写估计是这样的
sub proc
pop ax ;从stack取a 并放在AX寄存器中
pop bx ;从stack取b 并放在BX寄存器中
add ax,bx ; 计算a+b
ret //返回
sub endp
显然要调用这个函数,你应当先把b值push进stack,然后再push a
因为stack是先进后出的
所以调用汇编像这样
比如计算4+5
push 5;
push 4;
call sub; //返回值在AX中
在这个例子中先压5或先压4得到的结果没有变化
但大多数程序,如果参数的顺序错误将是灾难性的
因为不管什么高级语言最终都要编译成汇编语言,然后是机器语言
同样下面这个C程序,计算a+b值,必然会编译成上面的汇编代码
int sub(int a ,int b) {return a+b;}
所以C在调用这个函数sub时,必须要压栈(即传入参数)但这些工作,在C语言里,并不需要你来完成.你只要写出
sub(7,9);
编译器在编译成汇编时就会自动完成相关的压栈工作.
根据函数调用方式和参数压入顺序目前存在三种约定:
stdcall
cdecl
fastcall
这都相关压栈顺序和栈的清理工作约定
他们的细节都不相同,但有一点是肯定的,参数比须从右向左压入栈中
stdcall中 函数必须自已清理栈
cdecall 由调用者清除堆栈 C的默认函数调用方式 所以这样C支持可变参数
fastcall 是把函数参数列表的前三个参数放入寄存器eax,edx,ecx,其他参数压栈
源代码:
int function(int a, int b)
{
return a + b;
}
void main()
{
function(10, 20);
}
1.__cdecl
_function
push ebp
mov ebp, esp
mov eax, [ebp+8] ;参数1
add eax, [ebp+C] ;加上参数2
pop ebp
retn
_main
push ebp
mov ebp, esp
push 14h ;参数 2入栈
push 0Ah ;参数 1入栈
call _function ;调用函数
add esp, 8 ;修正栈
xor eax, eax
pop ebp
retn
2.__fastcall
@function@8
push ebp
mov ebp, esp ;保存栈指针
sub esp, 8 ;多了两个局部变量
mov [ebp-8], edx ;保存参数 2
mov [ebp-4], ecx ;保存参数 1
mov eax, [ebp-4] ;参数 1
add eax, [ebp-8] ;加上参数 2
mov esp, ebp ;修正栈
pop ebp
retn
_main
push ebp
mov ebp, esp
mov edx, 14h ;参数 2给EDX
mov ecx, 0Ah ;参数 1给ECX
call @function@8 ;调用函数
xor eax, eax
pop ebp
retn
3.__stdcall
_function@8
push ebp
mov ebp, esp
mov eax, [ebp] ;参数 1
add eax, [ebp+C] ;加上参数 2
pop ebp
retn 8 ;修复栈
_main
push ebp
mov ebp, esp
push 14h ;参数 2入栈
push 0Ah ;参数 1入栈
call _function@8 ;函数调用
xor eax, eax
pop ebp
retn