1. 程式人生 > >[C/C++]函式如何返回struct或class物件

[C/C++]函式如何返回struct或class物件

本文寫於我對C++尚不是很瞭解的時期,所以文中存在很多漏洞。為了避免浪費你的時間,請繞道!

所有的C、C++教科書都警告我們:不要通過函式來返回struct或 class物件,否則會造成記憶體複製以及複製建構函式的呼叫,降低效能。相信這句話已經成為了一個常識,大家都能牢記於心。然而,有時候我們不得不違反這個警告,例如,通過函式獲取一個std::string物件(以個人的經驗而言,這種情況是很常見的,我經常要通過函式建立一個新的物件)。不知道從什麼時候起,當我面對這種情況的時候會通過引用來獲取這個物件,像這樣:

1 2 std::string GetString();
std::string& str = GetString();

這樣子給我的感覺會好一點,讓我覺得物件的複製次數少了。然而這只是一種憑空猜想,沒有經過任何證實。為了弄清楚這樣做究竟會不會帶來效能的提升,我決定研究一下函式是如何返回struct或class物件的。最好的研究途徑當然是反彙編編譯器生成的機器碼了。

我的實驗環境是Visual Studio 2010,所有程式碼都是Debug版本的,因為這樣生成的機器碼是最原始的,沒有經過任何優化,可以顯示出真實的情況。而Release版本的機器碼經過了優化,已經是“面目全非”,所以本文不考慮該版本。另外,對於struct來說,Visual Studio 2010 的C編譯器和C++編譯器生成的程式碼是一樣的,所以本文所有程式碼都通過C++編譯器來編譯。注意,使用不同的編譯器可能會有不同的結果!

如何返回struct物件

首先來看一下函式如何返回struct物件。分兩種情況:第一種情況是struct的大小是1位元組、2位元組或4個位元組,可以放到al、ax或eax暫存器中;第二種情況是struct的大小不是上面提到的三個值,不能放到暫存器中(包括3個位元組的)。要注意,這裡所說的“大小”是指在記憶體中經過對齊後的大小,而不是定義的大小。如果沒有特別說明,下文提到的大小也是指經過對齊後的大小。

第一種情況:struct可以放到暫存器中

下面是第一種情況的典型例子,struct的大小是4個位元組:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 struct S { int Value; }; S GetS(int value) { S s; s.Value = value; return s; } int wmain() { S s = GetS(10); }

下面是GetS函式的部分彙編程式碼:

1 2 3 4 5 6 ;s.Value = value; mov         eax,dword ptr [value]  mov         dword ptr [s],eax ;return s; mov         eax,dword ptr [s]

可以看到,s是直接通過eax來返回的,因為它的大小恰好可以放進eax暫存器中。

下面是S s = GetS(10);的彙編程式碼:

1 2 3 4 5 6 push        0Ah                       ;引數10入棧 call        GetS (8D1019h)            ;呼叫GetS函式  add         esp,4                     ;釋放參數空間 mov         dword ptr [ebp-0D4h],eax  ;將返回值儲存到臨時空間 mov         eax,dword ptr [ebp-0D4h]  ;從臨時空間裡取出返回值

相關推薦

[C/C++]函式如何返回structclass物件

本文寫於我對C++尚不是很瞭解的時期,所以文中存在很多漏洞。為了避免浪費你的時間,請繞道! 所有的C、C++教科書都警告我們:不要通過函式來返回struct或 class物件,否則會造成記憶體複製以及複製建構函式的呼叫,降低效能。相信這句話已經成為了一個常識

c++中memset給一個structclass初始化,賦0

memset函式的用法 將緩衝區設定為指定的字元。 下面是網上常見的說法,也就是memset函式的用法 函式功能是:將s所指向的某一塊記憶體中的前n個位元組的內容全部設定為ch指定的ASCII值,

C語言 函式返回一位陣列,二維陣列

方法一: 萬能的結構體:構造陣列的結構體,將函式型別定義為此型別 但是考試的時候應該不太方便寫結構體,寫不下也會很麻煩,故介紹方法二 方法二: 指標傳遞: 1、返回一維陣列 例子:將陣列每一位加一: #include<stdio.h> #define N 10 int

C函式返回陣列

C 語言不允許返回一個完整的陣列作為函式的引數。但是,可以通過指定不帶索引的陣列名來返回一個指向陣列的指標。如果您想要從函式返回一個一維陣列,必須宣告一個返回指標的函式,如下: int * myFunction() { } 另外,C 不支援在函式外返回區域性變數的地址,除非定義區域性

C++中函式返回陣列指標的幾種方法總結

因為陣列不能被拷貝,所以函式不能返回陣列。不過,函式可以返回陣列的指標或引用。返回陣列指標的方法有以下幾種:     1、方法一:使用類型別名。如下         typedef int arrt[10];//arrT是一個類型別名,它表示的型別是含有10個整數的陣列   

C語言函式返回值的實現方法和誤區

例項:你們認為這三個函式能正常返回嗎?  int func1(int a , int b) { int c = 0; c = a + b; return c; } char * func2() { char *strTmp = "abs"; return str

C++ 從函式返回陣列

C++ 不允許返回一個完整的陣列作為函式的引數。但是,您可以通過指定不帶索引的陣列名來返回一個指向陣列的指標。 如果想要從函式返回一個一維陣列,就必須宣告一個返回指標的函式,如下: int * myFunction() { . . . } 另外,C++ 不支援在函式外返回區域性變數的地址

C++虛擬函式、虛繼承、物件記憶體模型

虛擬函式的工作原理      虛擬函式的實現要求物件攜帶額外的資訊,這些資訊用於在執行時確定該物件應該呼叫哪一個虛擬函式。典型情況下,這一資訊具有一種被稱為 vptr(virtual table pointer,虛擬函式表指標)的指標的形式。vptr 指向一個被稱為 vtb

C++面試題一---StructClass的區別

C++中的struct對C中的struct進行了擴充,它已經不再只是一個包含不同資料型別的資料結構了,它已經獲取了太多的功能。 struct能包含成員函式嗎? 能! struct能繼承嗎? 能!! struct能實現多型嗎? 能!!! 既然這些它都能實現

誤人子弟篇之C語言函式返回值與引數傳遞

寫在開頭以免看到結尾你,此篇部落格純屬瞎扯,看看就可以了,不要當真哦! 如果搞過彙編,寫過子程式,那麼你就不用看了,因為看到最後你會發現,在彙編中你有很多方法去返回值,傳遞引數,而在高階語言中,編譯器只是選擇了其中的一種而已,而這篇部落格也寫的毫無邏輯,簡直喪盡天良,草菅人

程式設計基礎-------C語言函式返回二維陣列的做法

在C語言中,有時我們需要函式的返回值為一個二維陣列。這樣外部函式接收到這個返回值之後,可以把接收到的二維陣列當成矩陣操作(外部函式不可用普通的一級指標接收返回值,這樣的話,外部函式將不知道它具有二維性)。方法如下: 法1.沒有使用typedef型別定義 #inc

如何讓C語言函式返回一個二維陣列

為了讓C語言函式返回一個二維陣列,有些人這樣定義函式: int **foo(int rows, int columns) 然後在函式中費勁心機拼出來一個這樣的malloc語句: int (*result)[columns] = (int (*)[c

C++ 從函式返回指標(函式返回區域性靜態變數的地址)

C++ 不支援在函式外返回區域性變數的地址,除非定義區域性變數為 static 變數。 錯誤程式碼: int main(){ int *p; p=funcGetPointer()

C++中函式返回值的引用型別與非引用型別的區別

返回值為引用型別的函式某些情況下可作為表示式的左值,而非引用的則一般不可以。 函式返回值若為引用型別,當返回的是函式的引用形參時,則是對函式外的變數的引用,函式可以作為表示式的左值(被賦予新值)。 而當函式返回的是非引用型別時,返回的值是函式內隱式生成的

java-靜態同步函式的鎖是Class物件

/* 如果同步函式被靜態修飾後,使用的鎖是什麼呢? * 通過驗證,發現不在是this。因為靜態方法中也不可以定義this * 靜態進記憶體是,記憶體中沒有本類物件,但是一定有該類對應的位元組碼檔案物件。 * 類名.class 該物件的型別是Class * 靜態的同步

(多執行緒-靜態同步函式的鎖是Class物件)

/* 如果同步函式被靜態修飾後,使用的鎖是什麼呢? 通過驗證,發現不在是this。因為靜態方法中也不可以定義this。 靜態進記憶體是,記憶體中沒有本類物件,但是一定有該類對應的位元組碼檔案物件。 類名.class 該物件的型別是Class 靜態的同

c / C++ 中的struct 和memcpy函式 class 物件成員變數記憶體是否連續

對於c語言中 使用memcpy 函式來拷貝一個struct結構並沒有什麼不妥 但是在c++ 中出現了物件的概念,所以 對於struct物件總會有些不同吧,相對於c的struct 如果完全一樣的話就沒有必要設計class了。 當然在c++ 中class和struct還是

C++】函式和結構--struct經典程式--傳遞結構和返回結構的程式碼示例(1)

結構和陣列的差異(基本概念)  為結構編寫函式比為陣列編寫函式要簡單得多。 結構是一個實體,被 看做一個整體,可以將一個結構賦給另一個結構。 函式可以返回結構。陣列名就是陣列第一個元素的地址,而結構名只是結構的名稱,要想獲得結構的地址,必須使用地址運算子& 然而,按

C++基礎知識(八)---函式返回值(返回值,返回指標,返回物件返回引用)---引用---複製建構函式(拷貝建構函式

一、函式返回值   1.返回值: int test () { int a=1; return a; }   返回值時最簡單的方式,它的操作主要在棧上,變數a在函式結束後會刪除,為了返回a的值,系統會在內部建立一個臨時變數儲存a的值,以返回給呼叫該函式的表示式,呼叫結束後變數便

C++函式返回臨時指標物件的隱患

現在編譯器一般對臨時物件有優化,可以直接返回並使用,之前為了方便,若是介面指標,直接返回臨時物件,因為使用雙指標或引用總是要多操作幾步,今天遇到了一個很大的隱患。 //被調函式 CATIPLMNavReference_var GetRefFromOcc(const CAT