第1个回答 2013-09-22
栈的操作是先进后出没错,那是针对压栈和弹栈只要有栈顶、栈底的指针,可以计算与栈顶(底)的距离从而对栈内任何元素直接操作。 可以把栈看作一个一维数组,只是栈和数组的增长方向不同,同时栈不用考虑下标越界的问题,压栈和弹栈只对最后一个元素进行操作,我们无需了解栈顶、栈底具体在哪里(实际上CPU有两个寄存器专门用来保存这两个地址),比如我们有一个数组a[],现在栈底指着a[底+0],栈顶指着a[底+10],执行一次压栈操作使数据保存在a[底+10],栈顶指下移一步,指向a[底+11]。如果我们知道有一个数据保存在a[底+5],我们可以通过它与栈顶(底)的距离直接引用它,而不用把后面的数都弹出来。 //int a=30, b=15;
00401038 mov dword ptr [ebp-4],1Eh
0040103F mov dword ptr [ebp-8],0Fh
//a=a+b;
00401046 mov eax,dword ptr [ebp-4]
00401049 add eax,dword ptr [ebp-8]
0040104C mov dword ptr [ebp-4],eax
第2个回答 2013-09-22
1、这个地址值也是一个值,不过这里返回的是一个局部变量的地址,函数调用完毕之后伴随着栈指针的复位,这次调用使用的局部变量空间就有可能被下次函数调用时使用并更改其值,因此返回局部变量的地址通常都是个坏主意。
2、函数在调用之后,划分出来的栈空间并不是只能通过push和pop来访问,而且对于局部变量的引用通常也不是使用push和pop,只要知道新划分出来的栈顶位置(通常是ebp保存这个值),就可以通过基址+偏移的方式对特定栈空间进行随机访问。
#include <stdio.h>
void __declspec(naked) fun( int a, int b )
{
__asm {
push ebp ;保存调用函数的栈顶
mov ebp, esp ;fun的栈顶保存在ebp里
sub esp, 10h ;减出来的这段空间就用来存局部变量,这里一共16字节的空间
mov [ebp-4], 1 ;把这16字节用作4个32位存储空间,存入4个int
mov [ebp-8], 2
mov [ebp-12], 3
mov [ebp-16], 4
mov eax, [ebp+8] ;ebp+8是第二个参数的位置,这里是b
add eax, [ebp+12] ;这是第一个参数a
mov esp, ebp ;这两句还原调用现场
pop ebp ;ebp恢复为main函数的栈顶
ret
}
}
int main()
{
int a;
fun( 5, 12 );
__asm mov a, eax;
printf( "%d\n", a );
}
局部变量是通过偏移来访问的,不需要压栈退栈,所以没有这个操作。
函数的返回值在c/c++里面是通过eax来返回的,比如return 1,那么1被存入eax,然后main里通过eax来获取这个值,局部变量的值也是一样的。本回答被网友采纳