2017-04-07 20 views
0

在下面的例子(試行here編譯器如果區分具有相同地址的嵌套對象,該如何區分?

#include <iostream> 
using namespace std; 

struct a { 
    struct b { 
     int b1; 
    }; 
    b a1; 
    int a2; 
}; 
int main() { 
    a test; 
    test.a1.b1 = 5; 
    test.a2 = 6; 

    std::cout<<&test<<" "<<&(test.a1); 
    // your code goes here 
    return 0; 
} 

無論是結構和其結構nestd具有相同的存儲器位置。這是有道理的,因爲要存儲在內存中的第一個元素是嵌套結構的一部分。

證明:0x7ffd895f86e0 0x7ffd895f86e0

我的問題是:如何編譯器知道存儲什麼類型的在這個位置上,是有從跟蹤在運行時這些信息的任何開銷可以預料?

+1

它知道是因爲你寫了'struct a'的定義,這使得清楚並且被編譯器理解。運行時不需要這些信息。 – nwp

+0

所以你說的a1和測試的位置是一樣的 - 但是這與結構a的第一個成員的位置相同,與結構的位置相同。當這樣放置時,它仍然是意想不到的? – UKMonkey

+0

編譯器實現具有關於如何組織嵌套結構的硬編碼知識。 – Peter

回答

2

如何:

struct a { 
    int x; 
    struct b { 
     int b1; 
    }; 
    b a1; 
    int a2; 
}; 

他們有相同的地址?不。不是因爲它們不同,而是因爲「struct」沒有二進制含義(在抨擊之前,請繼續閱讀)。當你的程序被編譯時,所有重要的是你的結構中的變量。編程語言有這種表面的東西叫做「結構」,讓你的工作變得簡單。但這不是真實的,除非你做了一些需要將它作爲一件事情來處理的事情(比如複製它),即使如此,生成的二進制代碼(用於運行時)也只會代表要複製的元素一個整體,而不是「結構」本身。

當你實例a那裏,這是怎麼看起來像在內存:

int x - int b1 - int a2 

它的塊內存整數。這不是結構。

您可以使用指針進行驗證。在你的代碼中:

*(int*)(&test) //is b1 
*((int*)(&test)+1) //is a2 

所以你看在內存中只有兩個整數是重要的。 PS:請注意,所有這一切都假設我們沒有處理多態,它增加了更多的表示vtable的內存塊。這是另一天的故事。

+0

這個描述適用於沒有優化開啓的明智平臺上的標準佈局類,但通過虛擬函數和虛擬繼承快速分解。 – Quentin

+0

@Quentin用虛擬的東西,這絕對會中斷,這就是爲什麼二進制接口是用C而不是C++完成的原因。但我認爲這很深。我要添加更多關於這方面的信息。 –

0

讓「畫」的結構看起來如何在內存中(連同「指針」的話):

 
+----+----+ 
| a1 | a2 | 
+----+----+ 
^ ^
| | 
| &test.a2 
| 
&test 
| 
&test.a1 

這應該希望相當明確如何兩種不同的結構可以佔用相同的內存。

應該指出,這隻適用於具有非虛函數的結構。虛函數可能會導致其他隱藏成員被包含在對象中。

0

實際上,您是通過編寫表達式(例如& test和&(test.a1))來明確告訴編譯器何種類型存儲在給定位置的。

1

忘記你正在處理結構的那一刻。編譯器如何知道某個特定的內存位置是否包含intfloat?從某種意義上說,事實並非如此。但在程序中,變量有一個類型類型告訴編譯器什麼操作對該變量有效。不管該對象的地址是什麼;重要的是該計劃所說的是什麼類型。所以:

int i = 3; 
i = i + 1; 

編譯器知道怎麼做,此外,由於節目中說對待命名iint值的存儲位置。

float f = 4.0; 
f = f + 1; 

編譯器知道怎麼做,此外,由於節目中說對待命名f作爲float值的存儲位置。

在你的例子中,test.a1.b1的類型爲int,因爲程序這麼說。而且test.a1有類型a :: b because the program said so. And測試has type a`因爲程序這麼說。

相關問題