函數的返回值保存在內存的什么區域


函數的返回值保存在內存的什么區域呢?

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM