关于 函数返回值储存和栈的问题

1、你在我的函数返回值储存的问题中提到函数内定义的变量,是由系统在栈中划分一个栈单元以供自动变量等存储值的。我们知道栈是一种特殊的数据结构,它不按地址进行操作,是按先进后出的方式操作。void main(){ int *fun(); printf("%x\n",fun()); printf("%x\n",&fun) printf("%d\n",*fun());} int *fun(){ int a=30,*p; int b=15; a=a+b; p=&a; return(p);}问题1:为什么?*fun()能返回给主函数一个地址值呢?不是说栈内不按地址操作吗?问题2:按栈操作原则,程序在调用*fun()是应该是先执行 int a=30,*p; 后执行int b=15 也就是说,系统是先将a压入栈内,然后将b压入栈内,那a+b怎么解释,照理说应该是将a从栈中调入到CPU的寄存器中,再将b调入寄存器中,然后进经逻辑算术部件运算,得到结果。暂存在寄存器中。这样问题就来了,因为栈是先进后出,b还没从栈中退出,那么a怎么会先出栈呢?还是这里先将b调入寄存器,后调入a。这样的话a+b 不是变成从右向左结合了。

栈也是内存,是内存就有地址,栈用主要用于函数调用时保存CPU寄存器状态压入函数调用参数和局部变量第一个问题,函数调用与执行时会用到栈,结束时将栈的内存地址(指针)返回没什么问题,主要是指针指向的是一个过期的地址,这个地址的数据可能在别的函数被调用时被意外的被更改,所以不要用指向局部变量的指针,有程序崩溃的危险性第二个问题 不见得申请一个局部变量就会压入堆栈,有些计算直接就在CPU寄存器里就完成了,并且虽说栈是后进先出但不是说访问栈非要从最后一个开始向前一个一个的访问,只要知道相对位置一样可以先读a 再读b 把程序写好,编译,对着汇编仔细对照吧
温馨提示:答案为网友推荐,仅供参考
第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来获取这个值,局部变量的值也是一样的。本回答被网友采纳
相似回答