2013-11-02 17 views
0

我正在編寫代碼,並意識到我可以「訪問」與數組大小相同或更大索引的數組元素。爲什麼這不會產生錯誤?爲什麼我可以在C++中訪問大於數組大小的數組索引?

例如,

#include <iostream> 
using namespace std; 

int main() 
{ 
    int b_array[5] = {1, 2, 3, 4, 5}; 


    cout << b_array[5] << endl // Returns 0 
     << b_array[66] << endl; // Returns some apparently random value. 

    return 0; 
} 
+9

未定義的行爲。任何事情都可能發生。 – 0x499602D2

+1

這是未定義的行爲。無論在運行時發生什麼都是錯誤。 – juanchopanza

+0

爲什麼編譯器允許這樣做?考慮到它可能在for循環中偶然發生,不應該是非法的嗎? – ThisIsNotAnId

回答

4

C++不因招致的性能損失實現邊界檢查。
例如,vector模板包含一個at()函數,該函數檢查邊界,但比操作符[]慢約5倍。
低級語言傾向於強制程序員產生安全且無差錯的代碼以換取高性能。

+0

我明白了。很公平。 – ThisIsNotAnId

5

唯一的技術答案是「因爲C++語言規範說」。訪問超出界限值是未定義的行爲。你的個人品味無關緊要。

在「未定義的行爲」(C++規範中有很多)後面,需要讓編譯器開發人員根據他們必須運行的平臺實現不同的優化。

如果你認爲索引經常在循環中使用,如果你檢查邊界,你最終會檢查每個迭代,總是成功(從而浪費處理器時間)。

3

儘管像編譯器和/或靜態分析器可以檢測到訪問超出範圍那樣的簡單情況,但在編譯時通常不可行。例如,如果將數組傳遞給函數,它會立即衰減爲指針,編譯器在編譯時沒有機會進行邊界檢查。

另一種運行時邊界檢查比較昂貴:對每個訪問執行一次檢查會將簡單的內存解除引用轉換爲可能拖延的分支。要使事情變得更加困難,可以在指針上使用解引用運算符,即,甚至不能輕鬆知道在何處定位實際數組對象的大小。

其結果是,出界陣列的訪問行爲故意製造未定義:系統可以跟蹤這些訪問,但它不會必須。另外,系統在出界數組訪問方面實際做了什麼沒有指定,即它可以根據上下文做不同的事情。在很多情況下,它只會返回垃圾,這並不是太有用。但是,尤其是在適當的調試設置下,系統可能會在檢測到違規時改爲assert()

3

C++允許直接內存訪問您的程序。沒有爲您完成的邊界檢查。這可能是非常令人討厭的錯誤的原因,但與其他「更安全」的語言相比,它也非常有效。

數組不過是一個指向內存位置的指針。您嘗試訪問的索引(例如array [66]中的索引66)通過將66 * sizeof(int)添加到數組的起始地址來解決。最終計算出的地址是否在一定範圍內,超出了編譯器檢查的範圍。

換句話說,array [i]與C++中的*(array + i)相同。其實你可能會驚訝的發現array [i]也可以寫成i [array]

相關問題