C 程式變數作用域生命週期筆記

2021-07-03 15:21:11 字數 3422 閱讀 5474

1.c程式中通常將變數宣告在檔案的最開始;c++中變數宣告較隨意,可以在使用的時候宣告。

2.c程式中編譯的時候將變數寫入符號表,變數表,便於在函式方便的使用;c++是類安全處理,不能只在程式最開始的時候宣告變數,在建構函式有可能不明確輸入引數的定義,這時候就要支援在需要的時候宣告,而不是在函式的最開始。這個典例就是for迴圈中

例:定義在for迴圈中,屬於臨時性的工作,對於乙個for迴圈裡面定義的變數,他的生命週期是for迴圈,c++中標準的定義,編譯器會對此的處理是不同的:

對於vc6.0,下面的連續**是錯誤的。

3.生命週期和作用域(作用域就是乙個變數可以被引用的範圍,如:全域性作用域、檔案作用域、區域性作用域;而生命週期就是這個變數可以被引用的時間段)

4.可執行程式在儲存時(沒有調入到記憶體)分為**區(text)、資料區(data)和未初始化資料區(bss)3個部分

5.(1)**區(text segment)。存放cpu執行的機器指令(machine instructions)。通常,**區是可共享的(即另外的執行程式可以呼叫它),因為對於頻繁被執行的程式,只需要在記憶體中有乙份**即可。**區通常是唯讀的,使其唯讀的原因是防止程式意外地修改了它的指令。另外,**區還規劃了區域性變數的相關資訊。

(2)全域性初始化資料區/靜態資料區(initialized data segment/data segment)。該區包含了在程式中明確被初始化的全域性變數、靜態變數(包括全域性靜態變數和區域性靜態變數)和常量資料(如字串常量)。例如,乙個不在任何函式內的宣告(全域性資料):

int maxcount = 99;

使得變數maxcount根據其初始值被儲存到初始化資料區中。

static mincount=100;

這宣告了乙個靜態資料,如果是在任何函式體外宣告,則表示其為乙個全域性靜態變數,如果在函式體內(區域性),則表示其為乙個區域性靜態變數。另外,如果在函式名前加上static,則表示此函式只能在當前檔案中被呼叫。

(3)未初始化資料區。亦稱bss區(uninitialized data segment),存入的是全域性未初始化變數。bss這個叫法是根據乙個早期的彙編運算子而來,這個彙編運算子標誌著乙個塊的開始。bss區的資料在程式開始執行之前被核心初始化為0或者空指標(null)。例如乙個不在任何函式內的宣告:

long sum[1000];

將變數sum儲存到未初始化資料區。

圖3-1所示為可執行**儲存時結構和執行時結構的對照圖。乙個正在執行著的c編譯程式占用的記憶體分為**區、初始化資料區、未初始化資料區、堆區和棧區5個部分。

(1)**區(text segment)。**區指令根據程式設計流程依次執行,對於順序指令,則只會執行一次(每個程序),如果反覆,則需要使用跳轉指令,如果進行遞迴,則需要借助棧來實現。

**區的指令中包括操作碼和要操作的物件(或物件位址引用)。如果是立即數(即具體的數值,如5),將直接包含在**中;如果是區域性資料,將在棧區分配空間,然後引用該資料位址;如果是bss區和資料區,在**中同樣將引用該資料位址。

(2)全域性初始化資料區/靜態資料區(data segment)。只初始化一次。

(3)未初始化資料區(bss)。在執行時改變其值。

(4)棧區(stack)。由編譯器自動分配釋放,存放函式的引數值、區域性變數的值等。其操作方式類似於資料結構中的棧。每當乙個函式被呼叫,該函式返回位址和一些關於呼叫的資訊,比如某些暫存器的內容,被儲存到棧區。然後這個被呼叫的函式再為它的自動變數和臨時變數在棧區上分配空間,這就是c實現函式遞迴呼叫的方法。每執行一次遞迴函式呼叫,乙個新的棧框架就會被使用,這樣這個新例項棧裡的變數就不會和該函式的另乙個例項棧裡面的變數混淆。

(5)堆區(heap)。用於動態記憶體分配。堆在記憶體中位於bss區和棧區之間。一般由程式設計師分配和釋放,若程式設計師不釋放,程式結束時有可能由os**。

之所以分成這麼多個區域,主要基於以下考慮:

乙個程序在執行過程中,**是根據流程依次執行的,只需要訪問一次,當然跳轉和遞迴有可能使**執行多次,而資料一般都需要訪問多次,因此單獨開闢空間以方便訪問和節約空間。

臨時資料及需要再次使用的**在執行時放入棧區中,生命周期短。

全域性資料和靜態資料有可能在整個程式執行過程中都需要訪問,因此單獨儲存管理。

堆區由使用者自由分配,以便管理。

下面通過一段簡單的**來檢視c程式執行時的記憶體分配情況。相關資料在執行時的位置如注釋所述。

int a = 0; //a在全域性已初始化資料區

char *p1; //p1在bss區(未初始化全域性變數)

main()

作用域:全域性作用域(全域性變數只需在乙個原始檔中定義,就可以作用於所有的原始檔。)

生命週期:程式執行期一直存在

引用方法:其他檔案中要使用必須用extern 關鍵字宣告要引用的全域性變數。

記憶體分布:全域性資料區

注意:如果在兩個檔案中都定義了相同名字的全域性變數,連線出錯:變數重定義

例子:

int g_ivalue = 1;

extern int g_ivalue;

int main()

全域性靜態變數

作用域:檔案作用域(只在被定義的檔案中可見。)

生命週期:程式執行期一直存在

記憶體分布:全域性資料區

定義方法:static關鍵字,const 關鍵字

注意:只要檔案不互相包含,在兩個不同的檔案中是可以定義完全相同的兩個靜態變數的,它們是兩個完全不同的變數

例子:const int ivalue_1;

static const int ivalue_2;

static int ivalue_3;

int main()

靜態區域性變數

作用域:區域性作用域(只在區域性作用域中可見)

生命週期:程式執行期一直存在

記憶體分布:全域性資料區

定義方法:區域性作用域用中用static定義

注意:只被初始化一次,多執行緒中需加鎖保護

例子:void function()

區域性變數

作用域:區域性作用域(只在區域性作用域中可見)

生命週期:程式執行出區域性作用域即被銷毀

記憶體分布:棧區

注意:auto指示符標示

還有一點要說明,掌握static關鍵字的使用很關鍵。以下是引用別人的一些經驗之談:

tips:

若全域性變數僅在單個c檔案中訪問,則可以將這個變數修改為靜態全域性變數,以降低模組間的耦合度;

若全域性變數僅由單個函式訪問,則可以將這個變數改為該函式的靜態區域性變數,以降低模組間的耦合度;

設計和使用訪問動態全域性變數、靜態全域性變數、靜態區域性變數的函式時,需要考慮重入問題,因為他們都放在靜態資料儲存區,全域性可見;

如果我們需要乙個可重入的函式,那麼,我們一定要避免函式中使用static變數(這樣的函式被稱為:帶「內部儲存器」功能的的函式)

函式中必須要使用static變數情況:比如當某函式的返回值為指標型別時,則必須是static的區域性變數的位址作為返回值,若為auto型別,則返回為錯指標。

作用域 生命週期

作用域 能夠被使用的範圍 生命週期 生命的誕生和死亡 在類裡頭,先使用變數,後期到main裡幫助建立生命 在main裡頭作用域的範圍小於等於生命週期的範圍,在使用作用域之前已經預設存在生命週期了 作用域是不考慮生命週期的,因為作用域的線路比執行時候來的條數廣 作用域是製造多條線路,生命週期是執行一條...

C語言變數作用域和生命週期

1 c語言不支援對形參變數的引用,也就是說,形參變數的作用域僅在於函式定義域內 2 有的c語言編譯器支援對變數不在函式開始的時候定義 3 全域性變數可以作為函式間通訊的乙個工具 4 全域性變數可以通過減少函式形引數,較少記憶體空間,較少傳遞資料的時間消耗 5 動態變數的生命週期和其所在的汗水一樣 6...

變數的生命週期與作用域

變數的型別 區域性變數和全域性變數 對於c 變數來說,有兩個屬性非常重要 作用域和生命週期,它們從兩個不同的維度描述了乙個變數的時間和空間。區域性變數也稱為內部變數。區域性變數是在函式內作定義說明的。其作用域僅限於函式內,離開該函式後再使用這種變數是非法的。全域性變數也稱為外部變數,它是在函式外部定...