第一次寫博客之類的東西,主要是爲了記錄本身的學習過程,以便於記憶的加深和與各位大神進行探討,學習更多的東西。html
本次上傳主要是關於靜態局部變量的初始化問題。多線程
首先,靜態局部變量和全局變量同樣,數據都存放在全局區域,因此在主程序以前,編譯器已經爲其分配好了內存,但在C和C++中靜態局部變量的初始化節點又有點不太同樣。在C中,初始化發生在代碼執行以前,編譯階段分配好內存以後,就會進行初始化,因此咱們看到在C語言中沒法使用變量對靜態局部變量進行初始化,在程序運行結束,變量所處的全局內存會被所有回收。而在C++中,初始化時在執行相關代碼時纔會進行初始化,主要是因爲C++引入對象後,要進行初始化必須執行相應構造函數和析構函數,在構造函數或析構函數中常常會須要進行某些程序中須要進行的特定操做,並不是簡單地分配內存。因此C++標準定爲全局或靜態對象是有首次用到時纔會進行構造,並經過atexit()來管理。在程序結束,按照構造順序反方向進行逐個析構。因此在C++中是能夠使用變量對靜態局部變量進行初始化的。函數
後面再來談談另外一個問題,假如咱們在一個循環中,定義了一個靜態局部變量並進行初始化,循環過程當中,編譯器怎麼知道當前的靜態局部變量已經初始化過了呢?學習
這個問題C和C++的處理方式也是不同的。C中編譯器會直接跳過這一個語句,由於在編譯的時候已經對靜態局部變量進行過度配空間並初始化,因此代碼執行過程當中根本不須要再次執行。而在C++中,編譯器會在編譯器分配內存後,在全局區域(當前靜態局部變量的地址)附近一樣分配一塊空間,進行記錄變量是否已經進行過初始化。之因此說附近是根據編譯器不一樣,處理方式不一樣致使的。在網上有博客介紹某種編譯器(該吧主並無透露編譯器名字),會在當前變量後面的一個字節進行改變,具體上代碼:spa
(Ps:若編譯器已經發現當前變量初始化,則直接將整行代碼跳過,若等式後面爲n++,則不會繼續執行++命令)線程
從地址內存中咱們能夠看到在變量地址的後面一個字節中,有一個01用來記載當前靜態變量是否初始化。調試
而在VS2012中,發現了一個很奇怪的現象,先上代碼。htm
這段代碼a爲變量,右側爲執行代碼的彙編語句,能夠看到先從0x00306214中提取出來值,若是是0,則會繼續執行,進行初始化,若是是1,則會跳過當前下面的動做,此處能夠看到標誌位地址是在變量地址以前0x80個字節,但繼續後面幾種狀況對象
能夠看到只要變量名稱發生改變,每次標誌位所在的地址與變量地址之間的差距變化都比較大。可見VS編譯器對標誌位地址的選擇是根據變量名稱變化的。具體選擇方法,還但願有鑽研過的大神指點一二。blog
上面說到的僅僅針對單線程的程序,若是在多線程下的執行,g++編譯器會在在初始化過程當中對標誌位進行加鎖控制,詳情參考一下 http://www.cnblogs.com/xuxm2007/p/4652944.html
在不肯定編譯器是否會對多線程環境下靜態局部變量初始化加鎖的狀況下,儘可能不要使用初始化的局部靜態變量,若是須要使用,則須要本身定義一個全局鎖進行管控,如一個線程正在對某個變量(對象)進行構造,另外一個線程須要直接避開構造。
第一次發此類分享類博客,若是有大神看出其中漏洞,請及時指出,以便於本人可以對這方面的瞭解更加深刻
補充:使用G++調試後,查看地址發現對於一個靜態局部變量,編譯器會開闢8個字節的大小的存放空間,同時存放位置恰好在變量前面的8個字節位置。如有兩個靜態局部變量,則從第一個靜態局部變量前16個字節,分別8個字節對應一個變量。用事實說話,上圖: