C 語言初學教材 - 第五章 變數的儲存類型

變數,也就是識別字,我們已經見過許多例子,例如取得迴圈變數、儲存結果的變數、接受使用者輸入的變數,或是利用 #define 定義的常數、利用 enum 定義的列舉數,或是自行定義的函數名稱,這些全都是屬於識別字。



常數、列舉數定義後直接是常數值,函數屬於功能模組,我們已經陸續討論過不少函數的參數及回傳值,現在,我們把焦點集中在通常定易於函數中的識別字,也就是變數。


每一個變數都有型態、名稱及所儲存的數值,除了這些,變數還有儲存類型、佔用期間、範圍、連結等特性,如下
特性說明
儲存類型分為自動型及靜態型,自動型的變數在離開所屬範圍後,資料就會被銷毀,靜態型則會保留原值
佔用期間變數可被使用的有效期限,有些只存在一下子,有些反覆的被建立、刪除,有些能保存到程式執行結束
範圍變數能夠被使用的區域
連結分成內部連結及外部連結,內部連結是指變數在單一原始檔的使用情況,外部連結則是多個原始檔的使用情況


C 語言有四個儲存類型指定詞,四個都屬於關鍵字,分別是 auto 、 register 、 static 及 extern ,利用這些儲存類型指定詞可以指定變數的儲存類型,同時連帶指定變數的佔用期間、範圍、連結等特性。


但是我們從來沒有用過任一個儲存類型指定詞,不是嗎?是的,因為 C 語言預設沒有添加任何儲存類型指定詞的宣告,全都屬於 auto ,所以,當宣告一個迴圈變數 i ,如下
int i;


等同於
auto int i;


auto 與 register 的儲存類型屬於自動型,而 static 及 extern 屬於靜態型。所謂自動型變數是指佔用期間與範圍都只在某一特定的程式區塊內,離開所屬的程式區塊,便無法再使用相關的自動型變數。


一般來說變數宣告時,沒有添加任何儲存類型指定詞都屬於 auto ,這個我們已經看過很多例子。若是將變數宣告為 register ,這是建議編譯器把變數放到電腦 CPU 的暫存器中,因為有可能經常運用 register 類型的變數,放到暫存器可以加快程式的執行。


然而許多編譯器本身會作最佳化的動作,因此就算沒有特別把經常使用的變數宣告為 register ,編譯器自己也會直接把這些變數設定為 register ,也就是執行時直接放到暫存器裡。


所謂的靜態型變數就是程式執行期間都會保有其值,例如以下程式將函數 test1() 中的變數 a 宣告為 static
#include <stdio.h>

void test1(void);
void test2(void);

int main(void)
{
    test1();
    test2();
    test1();
    test2();
    test1();
    test2();
    test1();
    test2();
    test1();
    test2();
    test1();
    test2();
    test1();
    test2();
    test1();
    test2();
    
    return 0;
}

void test1(void)
{
    static int a = 0;
    printf("在 test1() , a = %d\n", a++);
}

void test2(void)
{
    int a = 0;
    printf("在 test2() , a = %d\n", a++);
}

/* 《程式語言教學誌》的範例程式
    http://pydoing.blogspot.com/
    檔名:statictest.c
    功能:示範靜態變數的使用
    作者:張凱慶
    時間:西元2010年7月 */ 


編譯後執行,如下



宣告為 static 的變數 a 會一直保有原值,因此每一次呼叫函數 test1() , a 都會遞增,而在函數 test2() 的自動型變數 a ,隨著每一次呼叫 test2() 都會重新被建立賦予初值。


static 是用為內部連結,我們在往後的部份才會介紹用為外部連結的 extern 。


問題與討論
  1. 說明變數具備的各項特性。
  2. 靜態型變數跟自動型變數有何不同?




沒有留言: