static全域性變數與普通的全域性變數

2021-07-12 07:09:57 字數 3811 閱讀 4484

一、程式的記憶體分配

乙個由c/c++編譯的程式占用的記憶體分為以下幾個部分:

1、棧區(stack)—

由編譯器自動分配釋放

,存放函式的引數值,區域性變數的值等。其操作方式類似於資料結構中的棧。 2

、堆區(heap)—

一般由程式設計師分配釋放,

若程式設計師不釋放,程式結束時可能由os**

。注意它與資料結構中的堆是兩回事,分配方式倒是類似於鍊錶。 3

、全域性區(靜態區)(static)— 全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態變數在一塊區域,

未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。程式結束後有系統釋放 4

、文字常量區

— 常量字串就是放在這裡的。

程式結束後由系統釋放。 5

、程式**區 — 存放函式體的二進位制**。

二、例子程式

int a = 0;

全域性初始化區

char *p1;

全域性未初始化區

main()

三、從作用域看:

全域性變數具有全域性作用域。全域性變數只需在乙個原始檔中定義,就可以作用於所有的原始檔。當然,其他不包含全域性變數定義的原始檔需要用extern 關鍵字再次宣告這個全域性變數。

區域性變數也只有區域性作用域,它是自動物件(auto),它在程式執行期間不是一直存在,而是只在函式執行期間存在,函式的一次呼叫執行結束後,變數被撤銷,其所占用的記憶體也被收回。

靜態區域性變數具有區域性作用域,它只被初始化一次,自從第一次被初始化直到程式執行結束都一直存在,它和全域性變數的區別在於全域性變數對所有的函式都是可見的,而靜態區域性變數只對定義自己的函式體始終可見。

靜態全域性變數也具有全域性作用域,它與全域性變數的區別在於如果程式包含多個檔案的話,它作用於定義它的檔案裡,不能作用到其它檔案裡,即被static關鍵字修飾過的變數具有檔案作用域。這樣即使兩個不同的原始檔都定義了相同名字的靜態全域性變數,它們也是不同的變數。

從分配記憶體空間看:

全域性變數,靜態區域性變數,靜態全域性變數都在靜態儲存區分配空間,而區域性變數在棧裡分配空間。

從以上分析可以看出, 把區域性變數改變為靜態變數後是改變了它的儲存方式即改變了它的生存期。把全域性變數改變為靜態變數後是改變了它的作用域,限制了它的使用範圍。因此static 這個說明符在不同的地方所起的作用是不同的。

四、總的來說就是:

1、生存週期不同

2、作用範圍不同

3、分配方式不同

----------------------------------------------

再來看下堆和

棧的不同:

1、分配方式不同;

2、空間大小不同;

3、分配效率不同;

4、能否產生碎片不同;

5、生長方向不同;1、

分配方式不同 棧:

由系統自動分配。 例如,宣告在函式中乙個區域性變數 int b; 系統自動在棧中為b開闢空間

堆:需要程式設計師自己申請,並指明大小,在c中malloc函式

如p1 = (char *)malloc(10);

在c++中用new運算子

如p2 = (char *)new(10);

但是注意p1、p2本身是在棧中的。 

2、空間大小不同

一般來講在32位系統下,堆記憶體可以達到4g的空間,從這個角度來看堆記憶體幾乎是沒有什麼限制的。但是對於棧來講,一般都是有一定的空間大小的,例如,在vc6下面,預設的棧空間大小是1m。

3、分配效率

棧是機器系統提供的資料結構,計算機會在底層對棧提供支援:分配專門的暫存器存放棧的位址,壓棧出棧都有專門的指令執 行,這就決定了棧的效率比較高。堆則是c/c++函式庫提供的,它的機制是很複雜的,例如為了分配一塊記憶體,庫函式會按照一定的演算法(具體的演算法可以參考 資料結構/作業系統)在堆記憶體中搜尋可用的足夠大小的空間,如果沒有足夠大小的空間(可能是由於記憶體碎片太多),就有可能呼叫系統功能去增加程式資料段的記憶體空間,這樣就有機會分到足夠大小的記憶體,然後進行返回。顯然,堆的效率比棧要低得多。

4、碎片問題

棧:只要棧的剩餘空間大於所申請空間,系統將為程式提供記憶體,否則將報異常提示棧溢位。 

堆:首先應該知道作業系統有乙個記錄空閒記憶體位址的鍊錶,當系統收到程式的申請時, 

會遍歷該鍊錶,尋找第乙個空間大於所申請空間的堆結點,然後將該結點從空閒結點鍊錶中刪除,並將該結點的空間分配給程式,另外,對於大多數系統,會在這塊記憶體空間中的首位址處記錄本次分配的大小,這樣,**中的delete語句才能正確的釋放本記憶體空間。另外,由於找到的堆結點的大小不一定正好等於申請的大小,系統會自動的將多餘的那部分重新放入空閒鍊錶中。 

對於堆來講,頻繁的new/delete勢必會造成記憶體空間的不連續,從而造成大量的碎片,使程式效率降低。對於棧來講,則不會存在這個問題,因為棧是先進後出的佇列,他們是如此的一一對應,以至於永遠都不可能有乙個記憶體塊從棧中間彈出,在他彈出之前,在他上面的後進的棧內容已經被彈出。

5、生長方向

對於堆來講,生長方向是向上的,也就是向著記憶體位址增加的方向;對於棧來講,它的生長方向是向下的,是向著記憶體位址減小的方向增長。

堆和棧相比,由於大量new/delete的使用,容易造成大量的記憶體碎片;由於沒有專門的系統支援,效率很低;由於可能引發使用者態和核心態的切換,記憶體的申請,代價變得更加昂貴。所以棧在程式中是應用最廣泛的,就算是函式的呼叫也利用棧去完成,函式呼叫過程中的引數,返回位址,ebp和區域性變數都採用棧的方式存放。所以,我們推薦大家盡量用棧,而不是用堆。雖然棧有如此眾多的好處,但是由於和堆相比不是那麼靈活,有時候分配大量的記憶體空間,還是用堆好一些。

用static修飾的函式,本限定在本原始碼檔案中,不能被本原始碼檔案以外的**檔案呼叫。而普通的函式,預設是extern的,也就是說,可以被其它**檔案呼叫該函式。

在函式的返回型別前加上關鍵字static,函式就被定義成為靜態函式。普通 函式的定義和宣告預設情況下是extern的,但靜態函式只是在宣告他的檔案當中可見,不能被其他檔案所用。因此定義靜態函式有以下好處:

<1> 其他檔案中可以定義相同名字的函式,不會發生衝突。

<2> 靜態函式不能被其他檔案所用。

static全域性變數與普通的全域性變數有什麼區別?static區域性變數和普通區域性變數有什麼區別?static函式與普通函式有什麼區別?   

答:1) 全域性變數(外部變數)的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式, 靜態全域性變數當然也是靜態儲存方式。 這兩者在儲存方式上並無不同。這兩者的區別在於非靜態全域性變數的作用域是整個源程式, 當乙個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。 而靜態全域性變數則限制了其作用域, 即只在定義該變數的原始檔內有效, 在同一源程式的其它原始檔中不能使用它。由於靜態全域性變數的作用域侷限於乙個原始檔內,只能為該原始檔內的函式公用, 因此可以避免在其它原始檔中引起錯誤。   

2) 從以上分析可以看出, 把區域性變數改變為靜態變數後是改變了它的儲存方式即改變了它的生存期。把全域性變數改變為靜態變數後是改變了它的作用域,限制了它的使用範圍。                   

3) static函式與普通函式作用域不同,僅在本檔案。只在當前原始檔中使用的函式應該說明為內部函式(static),內部函式應該在當前原始檔中說明和定義。對於可在當前原始檔以外使用的函式,應該在乙個標頭檔案中說明,要使用這些函式的原始檔要包含這個標頭檔案   

綜上所述:

static全域性變數與普通的全域性變數有什麼區別:

static全域性變數只初使化一次,防止在其他檔案單元中被引用;   

static區域性變數和普通區域性變數有什麼區別:

static區域性變數只被初始化一次,下一次依據上一次結果值;   

static函式與普通函式有什麼區別:

static函式在記憶體中只有乙份,普通函式在每個被呼叫中維持乙份拷貝

static全域性變數與普通的全域性變數區別

static全域性變數與普通的全域性變數有什麼區別?static區域性變數和普通區域性變數有什麼區別?static函式與普通函式有什麼區別?答 全域性變數 外部變數 的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。這兩者在儲...

static全域性變數與普通的全域性變數的區別詳細解析

1 static全域性變數與普通的全域性變數有什麼區別?2 static區域性變數和普通區域性變數有什麼區別?3 static函式與普通函式作用域有什麼不同?4 static函式與普通函式有什麼區別?1 static全域性變數與普通的全域性變數有什麼區別?答 全域性變數的說明之前再加以static ...

static全域性變數與普通的全域性變數有什麼區別

static全域性變數與普通的全域性變數有什麼區別?static區域性變數和普通區域性變數有什麼區別?static函式與普通函式有什麼區別?答案 答 1 全域性變數 外部變數 的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式。...