2013-10-28 58 views
2

假設我們有下面的代碼片段內存addressation - 零值

int* p = new int[5]; 

,我們的代碼是在保護模式下運行。因此,位於我們的p變量中的地址不是物理地址,而是僅分配給我們應用程序的虛擬內存部分的地址。當然,我們的系統還可以防止內存違規嘗試。

在這些情況下,是否可以給一個「零」地址,所以我們將有p = 0,這將是正確的?當然,我正在考慮將0的值視爲nullptr,因此如果此地址是正確的,則可能會產生誤導。

事實上,是否有任何規則告訴我們什麼是合法的可尋址範圍?

當然還有另外一個原因沒有被賦予這個值,但我不知道我是否正確 - 在C(C++)中,指向零值的指針被特殊處理,所以我們如何注意到如果我們的指針指向已分配的內存,或者它的值爲零,因爲它是nullptr

+0

這裏真正的問題是什麼,你是否可以相信'p == 0'意味着分配失敗? –

+0

是的,其實我的問題的一部分是「你是否可以相信'p == 0'意味着分配失敗?」。 –

回答

3

是否可以給出一個「零」地址,所以我們會有p = 0,這將是正確的?

我認爲你混淆了虛擬內存管理的物理和邏輯端。

在邏輯側,你的程序被保證從未看到,比較等於零的指針:

6.3.2.3(3)定義整數常量表達式0並且這樣的表達式轉換爲(無效* )爲null指針常量。如果一個空指針常量被轉換爲一個指針類型,那麼稱爲空指針的結果指針將被保證與指向任何對象或函數的指針進行比較。

但是在物理方面,沒有這樣的限制:沒有什麼能夠阻止虛擬內存管理系統給你的程序一個物理地址爲零的內存塊。但是,該物理地址永遠不會出現在與指針常量零值相匹配的虛擬地址上:物理地址對於虛擬內存管理系統而言對程序隱藏,並且保證與指針常量零對應的虛擬地址不會被由編譯器分配給你的程序。

+0

謝謝。整個我的問題是關於內存管理的邏輯方面。當然我知道邏輯地址並不等於物理方面,所以你的回答充滿了我的疑惑。 –

2

常量'0'表示空指針。這不是必然儘管存儲爲指針中的文字值0x00000000。所以理論上你可以得到0x00000000作爲你的對象的地址,並且如果將常量0存儲到指針中存儲空指針作爲一個不同的值,那將是有效的。

在實踐中,我沒有發現任何編譯器,但我知道。

+0

謝謝。事實上,我對現實生活中的情況感興趣,甚至更好,將系統編譯器與可能發生這種情況的系統編譯器配對。 –

+0

*如果將常量0存儲到指針中,則該函數有效* - 應該將其重新設置爲存儲全0的位模式,而不要與int文字'0'混淆。文字'0'將被轉換爲空指針的模式,無論它是否全爲0。 –

1

爲基於C程序提供虛擬內存的運行環境通常不允許0x00000000(或其附近的任何東西)成爲有效地址。

你將不得不努力獲得一個指針,以獲得0x00000000的值,並且仍然有效!通常,這意味着手動將OS系統調用映射到虛擬內存(mmap,VirtualAlloc)。在某些情況下,操作系統具有防止映射特定頁面內存的安全措施。例如,在一些較舊版本的Windows中,您必須通過1作爲您想要映射的地址而不是0,而在較新版本中,只有在內核模式中設置了特殊位時才能執行此操作。在某些版本的Linux上,您必須先將mmap_min_addr設置爲0,然後才能映射該頁面。

0

是的,其實我的問題的一部分是「你是否可以相信p == 0意味着分配失敗?」。

默認情況下,如果new未能分配以指示錯誤,則會引發異常,因此檢查返回值沒有意義。如果你使用新的無投擲版本,那麼你保證返回的值不會是nullptr,所以測試會沒事的。

現在,關於使用返回的內存是否安全的更大問題,它可能會也可能不會。不同的操作系統實現在內存上過度使用,所以他們會爲應用程序提供比物理可用內存更多的內存,假設應用程序可能需要它時,可能會在其他地方釋放某些東西。考慮到這一點,如果你要求大量內存,即使它是由語言結構(new)和OS(下面的分配器實現)分配給你的,也不能保證你能夠使用它。