zoukankan      html  css  js  c++  java
  • 函数的返回值保存在内存的什么区域

    函数的返回值保存在内存的什么区域呢?

    1、结构体大小不超过4字节,那么仍然使用EAX寄存器传递返回值
    2.结构体超过4字节但不等于8字节时,调用者将首先在栈上分配一块能容纳结构体的临时内存块,然后在传递完函数参数后将该临时内存块的首地址作为隐含的第一个参数最后(因为压栈顺序是从右到左)压栈,接下的动作同前所述。当被调用函数返回时,它会通过第一个隐含参数寻址到临时内存块并将返回值拷贝到其中,然后将保存有返回值内容的临时内存块的首址存进eax寄存器中,
    3、结构体大小刚好为8个字节时编译器不再于栈上分配内存,而直接同时使用EAX和EDX两个寄存器传递返回值,其中EAX保存低4字节数据,EDX保存高4字节数据。

    函数在定义时,必有其返回类型,返回类型可以为数值型(指针是表示地址的数值),void类型。函数只能返回一个值,数值形式可以是4字节的整型,浮点,8字节大小的long long,还可以返回结构体类型。虽然返回的都是数值,但是其中的返回机制不同。

    函数的局部变量定义在栈中,栈的特点后进先出(LIFO)。局部变量所在的栈的高地址在下,低地址在上。从main开始,申请变量时栈顶指针向上移动,进入局部变量,局部变量的申请同在main函数中一样,一旦子函数执行完毕,则栈顶指针下移到进入局部变量时的位置,子函数所申请的局部变量空间都被回收。所以如果函数需要子函数中的一些值时,可以通过返回该数据来获得(用指针间接访问变量无需返回)。

    1)讨论整型,浮点型,指针等4字节大小的数值。

    以下一个函数来举例说明:

    int add(int x,int y){
          int z=x+y;
          return z;
    }

    int main(){
           int sum=add(3,4);
           return 0;
    }
    该函数返回部分的汇编代码:

    return z;

    001813F7 8B 45 F8             mov         eax,dword ptr [z] 
        return这一段中,可以看到z中计算好的数据移到eax寄存器中,由eax寄存器将值带给调用该函数的函数变量。

    在返回这些类型时,系统将该函数所要返回的值移到寄存器中,栈顶指针下移,栈中的局部变量都死亡,寄存器中的数据再返回给调用该函数的函数所要接收的变量。

    2)讨论longlong等8字节大小的数值。

        在32bit的编译环境中,eax寄存器一次性只能接受传递4字节大小的数据,而8字节的大小显然靠它一次性是不能完全拿到的。

    代码为将上述的int改为long long类型。

    函数返回部分的汇编代码:

    return z;

    000C1400 8B 45 F4             mov         eax,dword ptr [z]  
    000C1403 8B 55 F8             mov         edx,dword ptr [ebp-8]  
        该函数的返回机制与4字节的相似,只是由两个寄存器来返回该值,其中将long long字节分为两部分移到eax和edx两个寄存器,通过这两个寄存器将函数值返回。

    3)返回结构体类型的数据

        一个结构体变量中可以包含多个不同数据变量,其大小很容易超过8字节,如果靠多个寄存器来实现将值带回到调用函数中,很不现实。

    函数举例:

    typedef struct {
         ​int num;
         char name[19];
         char sex;
         float score;
    }student;

    student test(){
          student stu;
          strcpy(stu.name,"xiaoming");
          stu.num=1001;
          stu.score=99.9;
          stu.sex='M';
          return stu;
    }

    int main(){
        student su;
        su=test();
        return 0;
    }
    该函数的返回类型为student结构体类型,该类型的大小为28字节。

    函数返回部分的汇编代码:

    return stu;

    00DD3B81 B9 07 00 00 00       mov         ecx,7  
    00DD3B86 8D 75 DC             lea         esi,[stu]  
    00DD3B89 8B 7D 08             mov         edi,dword ptr [ebp+8]  
    00DD3B8C F3 A5                rep movs    dword ptr es:[edi],dword ptr [esi]  

    return stu;

    00DD3B8E 8B 45 08             mov         eax,dword ptr [ebp+8]
    在进入该子函数之前,系统在栈中为该函数留下一段内存,在函数返回该类型数据时,先是寄存器将其中的数据移到该段空间,子函数中的数据死亡,再由该段空间将值返回到调用函数的变量中。该方式的代价比较大,消耗了空间,并且在复制移值中也占用了cpu及寄存器等资源,所以指针间接访问来提高代码的效率。
     
    ————————————————
    版权声明:本文为CSDN博主「danxibaoxxx」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/danxibaoxxx/article/details/94445666

  • 相关阅读:
    HDU 3951 (博弈) Coin Game
    HDU 3863 (博弈) No Gambling
    HDU 3544 (不平等博弈) Alice's Game
    POJ 3225 (线段树 区间更新) Help with Intervals
    POJ 2528 (线段树 离散化) Mayor's posters
    POJ 3468 (线段树 区间增减) A Simple Problem with Integers
    HDU 1698 (线段树 区间更新) Just a Hook
    POJ (线段树) Who Gets the Most Candies?
    POJ 2828 (线段树 单点更新) Buy Tickets
    HDU 2795 (线段树 单点更新) Billboard
  • 原文地址:https://www.cnblogs.com/feng9exe/p/12527408.html
Copyright © 2011-2022 走看看