全局變量,就是指那些定義在函數之外的變量,當然也是定義與類之外的變量。
(1)全局變量會被自動初始化,函數中的變量不會被自動初始化,類中定義的那些成員變量(內建)也不會自動初始化。那麼這裡有一個疑問,為什麼要這樣設置?並且為什麼,進程內存區中,分為初始化了的全局變量和靜態變量,和未初始化的全局和靜態變量。
(2)全局變量如果加上static關鍵字,事情將會變得很奇妙。
我們知道,全局變量理論上是指應用程序級別的全局。普通的全局變量是面向整個程序的,當各個文件各自編譯,然後鏈接成一個可執行程序之後,全局變量的確是被所有文件中的“看到的”,但是,如果想讓別的文件在編輯程序的是否就能夠看到,(如果你不做然後措施,直接使用另外一個文件中定義的變量,那將通不過編譯)
有兩個辦法:
第一個就是#include方法,但是這個方法,其實是將文件合並成一個文件,並沒有正面回答。
第二個就是在要使用該變量的文件中聲明(extern)一個外部變量,這樣等於就是告訴編譯器,“該變量是有的,只是在另外一個文件中,等到鏈接的時候你就可以看到了。”這個extern必須要加,否則就是重新定義個變量,到時候連接會出現重定義問題。
但是,如果你在全局變量前加上static,那麼它的作用范圍就變小了,編程了文件范圍。這就會導致該變量是不容許別的文件通過extern聲明方式來操作。因為該變量對其它文件是不可見的。
我們所說的變量的生命周期和作用域時我們有這樣的說法:
1) 全局變量和靜態變量的生命周期為整個進程,他們都處在內存的同一個區域
2) 普通全局變量的作用域為全局(整個軟件,可跨域文件,其他文件想使用可以使用extern聲明),函數中的靜態變量的作用域為該函數。
3) 靜態全局變量,的作用域則被限制在該文件中,所以,這個時候其他文件通過extern想使用該文件是不行的,(就算成功啦,那是因為你引用了其他文件中的定義)。同時,由於作用域被限制在當前文件,所以,不同的文件定義自己的全局變量就不會擔心與其他文件出現沖突。
所以,這裡就有一個有關全局變量定義的標准了。
1) 如果你在這個文件中定義的全局變量不打算給別人用,那麼你就將它定義為static全局變量吧!因為這樣你不必擔心其他文件也定義了一個同名變量,在連接的時候出現重定義。
2) 如果你的全局變量是打算給其他文件使用的,那麼就不要加上static,因為這樣在其他文件中可以使用extern對該定義進行引用。
3) 這麼說來,static 和extern是不能同時用來修飾一個變量的,extern修飾表示該變量只是聲明,聲明它使用了其他文件的變量定義,static的修飾表示我這個變量(自己定義的),只能被當前文件訪問。兩者完全沖突,所以編譯器會報錯——‘n’的聲明中有相互沖突的限定符。
Extern有兩種用法:
(1) 與C一起使用 extern C ,來在C++中表達,在編譯的時候按照C的風格進行編譯。
(2) 於是普通修飾全局變量的聲明,(extern int n;)注意它只能是聲明,不能定義初始化,它聲明表示,該變量可以從另外一個文件中找到,現在大膽使用就行了。到時候(鏈接的時候)就可以找到了,所以我認為這個extern關鍵是來支持,當前文件可以通過編譯器的檢查。當前文件使用了另外一個文件內定義的東西,但是有不能直接#include它,所以這導致這種技術的出現。注意,必須有一個文件定義了該變量(int n;)如果沒有一個文件定義了它,那麼編譯的時候能夠通過,但是在連接的時候,文件找不到你給它的承諾,所以就會報錯——undefined reference to `n'。
Static的應用場景:
(1) 在C++面向對象中修飾成員函數或變量,這表明它所屬范圍為這個類,而不是對象。
(2) 在局部變量中(函數中)修飾變量,表示該變量是這個函數范圍內的不變的,而不是隨著每一次的函數呗調用而更新。所以你會發現,static修飾函數中的變量和修飾類中的成員有異曲同工之妙。函數每次被調用,類似於類每次被實例化。普通的成員都會是一個新的,而static成員與至始至終屬於該函數(類)。
(3) 在全局變量中修飾變量,表示該變量的作用范圍為當前文件,而不是整個程序。