2013-04-18 30 views
5

如果我有以下幾點: -傳遞一個結構的函數用C

struct foo 
{ 
    int a; 
    int *b; 
} bar; 

void baz(struct foo qux) 
{ 

} 

難道我就在想,通過barbaz()導致的bar本地副本被壓入堆棧?如果是這樣,這是什麼樣的副本?在C++中,我認爲它會調用複製構造函數或默認的拷貝構造函數,但我真的不知道這將如何在C中工作。

C是否有任何默認複製構造函數的概念,並且它是否具有名稱?能做些什麼來執行深層複製? (假設)。我能想到的唯一方法是實際進行深層複製,然後將其傳遞給函數。

通常,我會傳遞一個指向foo的指針,但我只是好奇它是如何工作的。此外,我認爲傳遞指針速度更快,可以節省內存,並且是進行此類操作時建議採取的行動方式。我猜這是一個淺拷貝;這可以改變嗎?

回答

4

我是否認爲將bar傳遞給baz()會導致本地副本被壓入堆棧?

是的。

我真的不知道如何做到這一點的C.工作

基本上原封不動地將與C++中的默認的拷貝構造函數;該副本的每個字段都使用原始對應字段進行初始化。當然,由於「似乎」規則,整個事情可能歸結爲memcpy

我的印象是,傳遞指針速度更快,可以節省內存,並且是進行此類操作時建議採取的行動方案。

對於較大的struct這通常是這種情況,但並不總是這樣;如果您的小字段很小,則複製的開銷可能小於間接開銷(同樣,由於C和C++的別名規則可能會阻止某些優化,因此使用指針參數可能代價高昂)。

我猜測它是淺拷貝;這可以改變嗎?

不,淺拷貝(盲目每個字段複製)是默認的拷貝構造函數會發生什麼(而用「深拷貝」你平時的意思也創造了指針/參考字段中引用的每個對象的副本)。

你的意思是「通過引用傳遞」,並且它不是缺省的允許最大的靈活性(以及與原始類型的傳遞的一致性)。如果你想通過引用傳遞一個指針(或C++中的引用),如果你只是爲了性能,通常const,否則你傳遞對象本身。

+0

p.s. C中沒有構造函數本身;只在C++中。在C中,您的數據結構將被簡單地逐個字節複製。 –

+0

@EdwardFalk:當然,事實上我談到*初始化*,而不是構造;另外,標準沒有規定「字節逐字節」的事實,它實際上說只有命名的字段才能被複制(即使在初始化之後,「結構對象的未命名成員具有不確定的值」,C99§6.7 .8¶9) - 即填充可能會或可能不會被複制。 –

+0

很好的解釋,我猜你不能覆蓋默認行爲來執行深層複製,如果這是必需的? – chrisw

1

是的本地副本被推送到堆棧。下面的工作示例對其餘部分進行了評論。

#include <stdio.h> 
    struct foo 
    { 
     int a; 
     int *b; 
    } bar; 
    void baz(struct foo qux) 
    { 
     bar.a = 2; // if its a different copy then printf on main should print 1 not 2. 
     *bar.b = 5; // if its a different copy then printf on main should print 5 not 4. since the place pointer pointing to is same 
    } 
    int main(){ 
     bar.a=1; 
     bar.b = (int*)malloc(sizeof(int)); 
     *bar.b = 4; 
     baz(bar); // pass it to baz(). now the copy of bar in the stack which is what baz going to use 
     printf("a:%d | b:%d\n",bar.a,*bar.b); 
     //answer is 2 and 5 
     /*So indeed it does a shallow copy thats why we lost the "4" stored in bar.b it did not created new space in heap to store "5" instead it used the same space that b was pointing to. 
     */ 
    return 0; 
    }