1. 程式人生 > >C語言:連結屬性與儲存型別

C語言:連結屬性與儲存型別

一、 連結屬性

C語言中連結屬性決定如何處理在不同檔案中出現的標示符。標示符的作用域與它的連結屬性有關,但這兩個屬性並不相同。

連結屬性有3種: external(外部),internal(內部) 和 none(無)。

1. none: 沒有連結的標示符,總是被當做單獨的個體,也就是說改標示符的多個宣告被當做不同的實體。

2. internal: 在同一個原始檔內的所有宣告中都指同一個實體,但位於不同原始檔的多個宣告則分屬不同的實體。

3. external: 標示符不論宣告多少次,位於幾個檔案都表示同一個實體。

舉一個簡單的例子對連結屬性進行說明,如下圖:


1. 在預設情況下,標示符b,c,f 的連結屬性為external, 其餘標示符的連結屬性則為none。因此,另一個原始檔也包含了標示符b的類似宣告並呼叫函式c,他們實際上訪問的是這個原始檔所定義的實體。f的連結屬性之所以是external,是因為它是函式名。這個原始檔中呼叫f,實際上將連結到其他原始檔所定義的函式,甚至這個函式的定義可能出現在某個函式庫。

2. 關鍵字extern和static用於在宣告中修改標示符的連線屬性。如果某個宣告在正常情況下具有external連結屬性,在它前面加上static關鍵字可以使它的連結屬性變為internal。例如,將b宣告為 

static int b;
那麼變數b就將為這個原始檔所私有。在其他原始檔中,如果也連結到一個叫做b的變數,那麼它所引用的是另一個不同的變數。

3. static只對預設連結屬性為external的宣告才有改變連結屬性的效果。例如,你儘管可以在變數e前面加上static關鍵字,但它的效果完全不一樣,因為e的預設連結屬性不是external。

二、 儲存型別

變數的儲存型別是指儲存變數值的記憶體型別。有三個地方可以用於儲存變數:普通記憶體、執行時堆疊、硬體暫存器。變數的預設儲存型別取決於它的宣告位置。

1. 凡是在任何程式碼塊之外宣告的變數總是儲存於靜態記憶體中,也就是不屬於堆疊的記憶體,這類變數稱為靜態(static)變數。靜態變數在程式執行之前建立,更確切的說,是在將可執行檔案載入到記憶體的時候建立,其在程式的整個執行期間始終存在。

2. 在程式碼塊內部宣告的變數的預設儲存型別是自動的(automatic), 也就是說它儲存於堆疊中,稱為自動變數。有一個關鍵字auto就是用於修飾這種儲存型別的,但它極少使用,因為程式碼塊中的變數預設情況下就是自動變數。在程式執行到宣告自動變數的程式碼塊時,自動變數才被建立,當程式的執行流離開程式碼塊時,這些自動變數便自行銷燬。在程式碼塊內部宣告的變數,如果給它加上static,可以使它的儲存型別從自動變為靜態。注意,修改變數的儲存型別並不表示修改改變數的作用域。它任然只能在該程式碼塊內部按名字訪問。函式的形式引數不能宣告為靜態,因為實參總是在堆疊中傳遞給函式。

3. 關鍵字register可以用於自動變數的宣告,提示它們應該儲存於機器的硬體暫存器而不是記憶體中。

三、 static關鍵字使用說明

注意到在“連線屬性”和“儲存型別”中都有可能使用到static關鍵字,因為我們有必要搞清楚在不同情況下,static關鍵字的作用。

1. 當它作用於函式定義時,或者用於程式碼塊之外的變數宣告時,static關鍵字用於修改標示符的連結屬性。

從external改為internal,但標示符的儲存型別和作用域不受影響。用這種方式宣告的函式或變數只能在宣告它們的原始檔中訪問。

2. 當它作用於程式碼塊內部的變數宣告時,static用於修改變數的儲存型別。

從自動變數修改為靜態變數,但變數的連結屬性和作用域不受影響。用這種方式宣告的變數在程式執行之前建立,並在程式的整個執行期間一直存在。

四、 作用域、儲存型別示例

我們就以下面的示例程式碼進行說明。


1. 第1行a的連結屬性為external,第二行extern在技術上並非必要,第三行的static關鍵字修改了c的預設連結屬性,把它改為internal。聲明瞭變數a和b(具有external連結屬性)的其他原始檔在使用這兩個變數時實際所訪問的是宣告與此處的這兩個變數。但變數c只能由這個原始檔訪問,因為它具有internal連結屬性。

2. 變數a,b,c 的儲存型別為靜態,表示它們並不儲存於堆疊中。因此,這些變數在程式執行之前建立,並一直保持它們的值,直到程式結束。

3. 第4行聲明瞭兩個標示符,d的作用域從第四行直到檔案結束。對於函式而言,儲存型別不是問題,因為程式碼總是儲存在靜態記憶體中的。引數e不具有連結屬性,所以我們只能從函式內部通過名字訪問它。

4. 第6~8行宣告區域性變數,所以它們的作用域到函式結束為止,它們不具有連結屬性,所以它們不能在函式的外部通過名字訪問。變數g的儲存型別是靜態,所以它在程式的整個執行過程中一直存在。當程式開始執行時,它被初始化為20。當函式每次被呼叫時,它並不會被重新初始化。

5. 第9行的宣告並不需要,這個程式碼位於第1行宣告的作用域之內。

6. 第12,13行程式碼塊宣告為區域性變數。它們都具有自動儲存型別,不具有連結屬性。

7. 第14行使全域性變數h在這個程式碼塊內可以被訪問。它具有external連結屬性,儲存於靜態記憶體中。

8. 第19,20行用於建立區域性變數。

9. 第25行聲明瞭函式i,它具有靜態連結屬性。

五、 作用域、連結屬性和儲存型別總結


六、 變數儲存區域分配圖

大家可以根據上述示例程式碼,將變數一一對應的放到指定的區域。