2016-10-18 42 views
1

嘗試以下32位的Ubuntu虛擬機上的代碼:爲什麼數組的內存地址總是增加?

static int a[0x1f0fff]; 
cout << &a[0x600000] << endl; 
cout << &a[0x800000] << endl; 
cout << &a[0x8fff00000] << endl; 

0x984a140 
0xa04a140 
0x7c4a140 

真的很困惑,該地址不繼續增加。

該數組位於堆,並打印什麼是虛擬內存地址。是因爲它超過了虛擬內存空間嗎?

此外,根據another answer,最後兩行代碼是索引到未分配內存的一部分。爲什麼沒有報告段錯誤?

+3

「爲什麼沒有報告段錯誤?」當程序訪問尚未分配的內存時會發生Segfaults錯誤。沒有段錯誤並不意味着你的程序是好的。只要你做錯了什麼,程序就不需要崩潰。 – xaxxon

+0

沒有保證。這是未定義的行爲。 –

+0

不要低估問題,因爲你認爲某人應該已經知道答案。如果您不滿意問題,請評論爲什麼。 – xaxxon

回答

3

您的十六進制表示法雖然華而不實,但不過是一種模糊處理(儘管十六進制文字的類型推斷規則不同於數字文字)。

你的代碼的行爲是undefined但也許不是你可能會想的原因。

注意&a[0x600000]實際上並沒有考慮它的地址之前試圖取消引用子虛烏有(0x600000)級a元素。編譯器需要評估表達式爲a + 0x600000但是:

將指針設置爲非數組中元素的地址a或者該數組末尾的一個是未定義的行爲。因此,編譯器可以輸出任何內容。

+0

謝謝。我明白了邏輯。未定義的行爲是不合理的。但是已經看到以下代碼被多次使用:'#define offsetof(TYPE,MEMBER)((size_t)&((TYPE *)0) - > MEMBER)'。這可以使用地址0嗎? – heLomaN

+1

@heLomaN:在C語言中肯定是可以的(在C語言中是慣用的),我不記得C++。也許這是一個問題。 – Bathsheba

+0

@heLomaN:'offsetof'是你的實現的一部分,必須是因爲你不能自己寫。作爲你實現的一部分,你的_particular_實現可以用這種方式使用'(TYPE *)0'。另一個常見的實現是'#define offsetof __builtin_offsetof' – MSalters

2

未定義的行爲不是段錯誤。你希望爲段錯誤。有時你會得到鼻子惡魔。

爲什麼這種特殊的行爲? 32位無符號數學模2^32。不保證會發生,但我確定這是編譯結果在這裏執行的操作。

+0

謝謝。我不應該嘗試未定義的代碼。但是數學不正確,0xa04a140 + 0x8fff00000 - 0x800000!= 0x7c4a140。可能因爲未定義。 – heLomaN

+0

@helo mod 2^32與'* sizeof(int)'它相等。指針算術在這裏每個'+ 1'都加上'+ sizeof(int)'。 – Yakk

1

此外,根據另一個答案,最後兩行代碼是索引到未分配的內存的一部分。爲什麼沒有報告段錯誤?

訪問陣列外的綁定是不確定的行爲,這意味着任何事情都可能發生,這也意味着有段錯誤的不能保證 - 有可能發生一次,它可能不是未來時有發生(這是爲什麼它被稱爲undefined)。

相關問題