C++面試題——const 和 static
雖說不太喜歡這種問語言特性的題目,但是國內好多公司貌似就喜歡問這個,還覺得問這個很高階,就把他們常問的一些東西寫下來做個總結,有的東西還是有些意思的,有些東西其實都沒個固定的答案。不出意外將會寫一個系列包括:
- const和static的區別
- iterator和引用的實現以及與指標的區別
- 從dynamic_cast說C++的虛機制和物件記憶體佈局
當然也保不齊出意外就不寫了。這裡面不會討論具體的C++語法問題,更多的是設計實現機制的東西,其實這些實現機制不是標準裡要求的,每種編譯器的實現機制可能都不一樣,有的書像《深度探索C++物件模型》是這方面比較有名的一本書,但是由於年代比較久遠了,在我的實驗中這本書的很多細節已經和當今的編譯器不一樣了。而許多介紹這方面東西的部落格也不見得和最新的編譯器實現一樣所以如果有興趣的話還是自己動手探索一下,不要過於相信書和別人寫的,本來這些東西就沒有標準答案。
先從個簡單的問題開始,const和static的區別。這其實是個很不好的題目,從語言的層面上講,這兩個東西不是個橫向可比的東西,他們的功能集合幾乎是正交的,不像所謂的引用和指標,迭代器和指標那樣有相關性,但是就是有面試官喜歡問。
由於這個問題實在不回答,就把static和const分別是怎麼做到的說一說。
static的特性主要有兩個,連線期被分配到了data段,即使是在函式呼叫中定義也不會在棧中產生,而是在程式載入期就被加入了記憶體。第二點就是編譯生成的目標檔案中不會將static變數加入到export表中,也就是說其他模組是不會訪問到這個static變數的。
具體來可以寫一個實驗程式,定義幾個全域性的普通變數和全域性的靜態變數,再在main函式裡定義幾個普通變數和靜態變數,開啟除錯模式觀察這些變數的地址,我是用VS2010除錯的,不同編譯器結果可能會有差別。可以發現全域性的靜態變數,區域性的靜態變數和全域性普通變數的地址是相互靠近的,main函式中的普通變數是在相隔較遠的另一個位置。由此可證明static變數是在和全域性變數相互靠近的區域,也就是程式的data端,而不是在棧空間內,這樣就保證這個變數不會隨著函式呼叫和返回的入棧出棧把static變數抹掉。
static第二個特點有點像private關鍵字,規定這個變數只能在本檔案中使用而不會被其他檔案使用,即便你在別的檔案中加入extern關鍵字也找不到這個變數。以為extern的實現機制是在連結時期通過程式依賴的目標檔案的符號匯出表尋找相應的符號,static變數不會加入符號表,別的檔案也就看不到這個符號。
const表面含義貌似是個常量,但實際上還是佔據一個記憶體位置的變數,但是它的值一般實在編譯時期就決定了,所以很多情況下就被編譯優化用一個常量代替了,根本沒有這個變數的蹤影。除非有這個變數的引用或者指標暗示這個所謂的常量可能會被修改才會佔用一個記憶體空間。
換句話說就是C++所謂的const只是在語言層面上提供一個無法修改的保障,這個保障就是說你直接修改這個變數編譯無法通過。而不是通過把這個變數放入只讀區域或者把存有這個變數的記憶體標成只讀來實現的。所以要突破這層保護是很容易的,包括C++自己也提供了const_cast,我們自己也可以通過指標來修改這個所謂const變數的值。
int main()
{
volatile const int a = 10;
int *c =(int*) &a;
*c = 5;
cout<<a<<endl;
return 0;
}
可以通過這個簡單的程式自己測試一下。
歡迎大家在討論區有血性的爭論、動手、拍磚、捅刀子,亮出你的看法來!本部落格已經全文RSS輸出,大家可以通過訂閱oilbeater.com/atom.xml即可獲得部落格更新。或者關注我的微博@oilbeater在上面我會通知我的部落格更新並且還會分享一些有意思的技術文章,歡迎大家關注。