函數返回值傳遞


出自《程序員的自我修養-鏈接、裝載與庫》P299

eax是函數傳遞返回值的一個通道。

1.對於小於4個字節的數據函數將返回值存儲在eax中。

2.5~8個字節對象的情況調用慣例都是采用eax和edx的聯合返回方式進行。

3.大於8個字節的返回類型,用一下代碼測試:

 1 typedef struct big_thing
 2 {
 3     char buf[128];
 4 }big_thing;
 5 
 6 big_thing return_test()
 7 {
 8     big_thing b;
 9     b.buf[] = 0;
10     return b;
11 }
12 
13 int main()
14 {
15     big_thing n = return_test();
16 }
  • 首先main函數在棧額外開辟了一片空間,並將這塊空間的一部分作為傳遞返回值的臨時對象,這里稱為temp
  • 將temp對象的地址作為隱藏參數傳遞個return_test函數
  • return_test 函數將數據拷貝給temp對象,並將temp對象的地址用eax傳出。
  • return_test返回以后,mian函數將eax 指向的temp對象的內容拷貝給n。

如果返回值的類型的尺寸太大,c語言在函數的返回時會使用一個臨時的棧上內存作為中轉,結果返回值對象會被拷貝兩次。因而不到萬不得已,不要輕易返回大尺寸對象。

 

再來看看函數返回一個C++對象會如何:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 struct cpp_obj
 5 {
 6     cpp_obj()
 7     {
 8         cout << "ctor\n";
 9     }
10 
11     cpp_obj(const cpp_obj& c)
12     {
13         cout << "copy ctor\n";
14     }
15 
16     cpp_obj& opearator=(const cpp_obj& rhs)
17     {
18         cout << "operator = \n";
19         return *this;
20     }
21 
22     ~cpp_obj()
23     {
24         cout << "dtor\n";
25     }
26 };
27 
28 cpp_obj return_test()
29 {
30     cpp_obj b;
31     cout << "before return\n";
32     return b;
33 }
34 int main()
35 {
36     cpp_obj n;
37     n = return_test();
38 }

運行后的輸出結果可以得出:函數返回之后,進行了一個拷貝函數的調用,以及一次operator=的調用,也就是說,仍然產生了兩次拷貝。因此C++的對象同樣會產生臨時對象。

在這段代碼中我們還能看到在c++返回一個對象時,對象要經過兩次拷貝構造函數的調用才能夠完成返回對象的傳遞,1次拷貝到棧上的臨時對象里,另一次把臨時對象拷貝到存儲返回值的對象里。在某些編譯器里,返回一個對象甚至要經過更多的步驟。

為了減少返回對象的開銷,C++提出了返回值優化(RVO)技術,可以將某些場合下的對象拷貝減少一次,例如:

1 cpp_obj return_test()
2 {
3     return cpp_obj();
4 }

目的是直接將對象的構造在傳出時使用的臨時對象上,減少一次復制過程。


免責聲明!

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



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