2012-02-11 78 views
1

在C函數中,調用函數時分配其本地內存,當函數完成時釋放本地內存。對於返回值的函數(例如int,string),返回地址的內存是否被分配和釋放,並且它是調用堆棧還是被調用堆棧的一部分,還是別的?C中的返回地址的內存分配Objective-C

請看下面的例子:

int* foo() 
{ 
    int _myInt; 
    return(&_myInt); 
} 

這個例子讓我完全困惑的內存是如何分配給返回地址返回一個指針。有人可以解釋嗎?

C和Objective-C相同嗎?

+2

沒有一個簡單的正確答案。您可以從[調用約定](http://en.wikipedia.org/wiki/Calling_convention)和[x86調用約定](http://en.wikipedia.org/wiki/X86_calling_conventions)開始。 – Blastfurnace 2012-02-11 06:22:45

+0

等一下,你在問如何傳遞參數和結果,或者關於指針返回的內存所有權? – Blastfurnace 2012-02-11 06:30:46

+0

確實返回地址按值或通過引用傳遞? – KMC 2012-02-11 06:39:41

回答

4

我不知道Objective-C,但是,對於標準C,返回值通常存儲在寄存器中。

當函數返回一個指針類型時,由開發人員確保指向的內存在調用後保持有效。

考慮下面的函數:

char* GetStr() 
{ 
    char buff[50]; 
    strcpy(buff, "Hello, World!"); 
    return buff; 
} 

該函數返回一個指針,指向本地存儲器,它被釋放在函數返回時。訪問該內存將構成未定義行爲的錯誤。

這也適用於您的示例,這是無效的。但由於int可以放入寄存器,因此您可以簡單地執行return _myInt;並直接返回值。

+0

可以通過將字符串緩衝區聲明爲static char buff [50]來解決這個問題。 – hotpaw2 2012-02-11 06:16:25

+0

@ hotpaw2:或者從堆中分配內存,或者在函數之外移動聲明,或者讓調用者提供緩衝區等。 – 2012-02-11 06:17:21

+1

是的,所有解決方案中,使得緩衝區「靜態」可能是最不可取的。它從煎鍋裏掉進火裏。 – StilesCrisis 2012-02-11 06:22:51

3

在Obj-C中,如果您通過alloc調用分配了一個對象,則標準做法是在返回之前自動釋放該對象,並將該方法命名爲調用方知道它正在獲取自動釋放對象的方式。如果調用者需要,那麼它可以再次保留該對象。

- (MyClass *)getMyAutoreleasedObject { 
    MyClass *obj = [[MyClass alloc] init]; 
    return [obj autorelease]; // caller needs to retain if needed 
} 

而且,如果你不那麼自動釋放你應該在調用者知道它必須釋放返回的對象這樣的方式命名方法。這是Obj-C嚴格遵循的慣例。

在C中,如果您在堆棧中分配內存,則該內存在調用者中無效。

int *func() { 
    int a[100]; 
    return a; // invalid in caller 
} 

你的例子有同樣的問題。調用者返回的內存無效。在這種情況下,您可以動態分配內存,並且調用者在完成時需要釋放內存。

int *func() { 
    int *a = (int *) malloc (100 * sizeof(int)); 
    return a; // caller must free(a) 
} 
3

參數傳遞給一個函數,返回值傳遞給調用者。這是如何完成的,完全取決於實施。該語言只需要它的作品,並沒有什麼可說的如何來做到這一點。

在具有可用寄存器和硬件輔助堆棧的系統上,這些通常用於來回傳遞值。

不同的類型可能會有不同的處理方式,例如某些CPU具有用於存放指針的專用地址寄存器或單獨的浮點寄存器。在這種情況下,這些類型的值可能與整數或結構值的處理方式不同。

傳遞值的大小也可能會影響它,小值可能適合寄存器,而較大值不適合。

請注意,堆棧不是實現的要求,它只需要使用其他方法來組織值和函數調用。

0

在您的示例函數中,任何對返回值的使用都會調用未定義的行爲,因爲指向對象的生存期已結束。調用此函數的唯一安全方法是不使用返回值,以便立即丟棄它。