全局變量,就是指那些定義在函數或類之外的變量,它可作為多個類或函數都需要共同使用的變量。
(1)全局變量會被自動初始化,函數中的變量不會被自動初始化,類中定義的那些成員變量(內建)也不會自動初始化。那麼這裡有一個疑問,為什麼要這樣設置?並且為什麼,進程內存區中,分為初始化了的全局變量和靜態變量,和未初始化的全局和靜態變量。
(2)全局變量如果加上static關鍵字,事情將會變得很奇妙。
我們知道,全局變量理論上是指應用程序級別的全局。普通的全局變量是面向整個程序的,當各個文件各自編譯,然後鏈接成一個可執行程序之後,全局變量的確是被所有文件中的“看到的”,但是,如果想讓別的文件在編譯程序的時候就能夠看到,(如果你不做然後措施,直接使用另外一個文件中定義的變量,那將通不過編譯)
有兩個辦法:
第一個就是#include方法,但是這個方法,其實是將文件合並成一個文件,並沒有正面回答。
第二個就是在要使用該變量的文件中聲明(extern)一個外部變量,這樣等於就是告訴編譯器,“該變量是有的,只是在另外一個文件中,等到鏈接的時候你就可以看到了。”這個extern必須要加,否則就是重新定義個變量,到時候連接會出現重定義問題。
但是,如果你在全局變量前加上static,那麼它的作用范圍就變小了,編程了文件范圍。這就會導致該變量是不容許別的文件通過extern聲明方式來操作。因為該變量對其它文件是不可見的。
我們所說的變量的生命周期和作用域時我們有這樣的說法:
1) 全局變量和靜態變量的生命周期為整個進程,他們都處在內存的同一個區域
2) 普通全局變量的作用域為全局(整個軟件,可跨域文件,其他文件想使用可以使用extern聲明),函數中的靜態變量的作用域為該函數。
3) 靜態全局變量,的作用域則被限制在該文件中,所以,這個時候其他文件通過extern想使用該文件是不行的,(就算成功啦,那是因為你引用了其他文件中的定義)。同時,由於作用域被限制在當前文件,所以,不同的文件定義自己的全局變量就不會擔心與其他文件出現沖突。
一直以來,有一個有關全局變量定義的標准:
1) 如果在這個文件中定義的全局變量不打算給別人用,那麼你就將它定義為static全局變量吧!因為這樣你不必擔心其他文件也定義了一個同名變量,在連接的時候出現重定義。
2) 如果你的全局變量是打算給其他文件使用的,那麼就不要加上static,因為這樣在其他文件中可以使用extern對該定義進行引用。
3) 這麼說來,static 和extern是不能同時用來修飾一個變量的,extern修飾表示該變量只是聲明,聲明它使用了其他文件的變量定義,static的修飾表示我這個變量(自己定義的),只能被當前文件訪問。兩者完全沖突,所以編譯器會報錯——‘n’的聲明中有相互沖突的限定符。
函數或變量在聲明時,並沒有給它實際的物理內存空間,它有時候可以保證你的程序編譯通過, 但是當函數或變量定義的時候,它就在內存中有了實際的物理空間,如果你在編譯模塊中引用的外部變量沒有在整個工程中任何一個地方定義的話, 那麼即使它在編譯時可以通過,在連接時也會報錯,因為程序在內存中找不到這個變量!你也可以這樣理解, 對同一個變量或函數的聲明可以有多次,而定義只能有一次!
在IDE開發工具大行其道的今天,對於編譯的一些概念很多人已經不再清楚了,很多程序員最怕的就是處理連接錯誤(LINK ERROR), 因為它不像編譯錯誤那樣可以給出你程序錯誤的具體位置,你常常對這種錯誤感到懊惱,但是如果你經常使用gcc,makefile等工具在linux或者嵌 入式下做開發工作的話,那麼你可能非常的理解編譯與連接的區別!當在VC這樣的開發工具上編寫完代碼,點擊編譯按鈕准備生成exe文件時,VC其實做了兩 步工作,第一步,將每個.cpp(.c)和相應.h文件編譯成obj文件;第二步,將工程中所有的obj文件進行LINK生成最終的.exe文件,那麼錯 誤就有可能在兩個地方產生,一個是編譯時的錯誤,這個主要是語法錯誤,另一個是連接錯誤,主要是重復定義變量等。我們所說的編譯單元就是指在編譯階段生成 的每個obj文件,一個obj文件就是一個編譯單元,也就是說一個cpp(.c)和它相應的.h文件共同組成了一個編譯單元,一個工程由很多個編譯單元組 成,每個obj文件裡包含了變量存儲的相對地址等 。