1. 程式人生 > >C語言變數儲存類

C語言變數儲存類

變數的儲存模型(儲存類)可以用變數的作用域以及它的連結儲存時期來描述。

作用域,描述了程式中可以訪問一個標示符的一個或者多個區域

  • 程式碼塊作用域:在程式碼塊中定義的變數,在該定義的程式碼塊中該變數可見
  • 函式原型作用域:對函式進行宣告的時候,其實在這個時候編譯器並不在乎引數變數名,而只是關心引數變數的型別
  • 檔案作用域:在所有函式之外定義的變數,包括main函式

連結,C語言變數具有外部連結、內部連結和空連線三種類型

  • 具有程式碼塊作用域和函式原型作用域的變數有空連結,它們由其定義所在的程式碼塊或者函式原型所私有
  • 具有檔案作用域的變數可能有內部連結或者外部連結,具有外部連結的變數可以在多個檔案的任何地方使用,具有內部連結變數可以在一個檔案中宣告之後的任何地方使用

儲存時期,C語言變數具有靜態儲存時期和自動儲存時期兩種儲存時期,如果一個變數具有靜態儲存時期,它在程式執行期間一直存在。具有檔案作用域的變數都具有靜態儲存時期如果在具有檔案作用域的變數前加上static表明連結型別為內部連結,不表明儲存時期。

C使用作用域、連結和儲存時期來定義了5種儲存類:自動、暫存器、具有程式碼塊作用域的靜態、具有外部連結的靜態、以及具有內部連結的靜態

自動變數:使用auto儲存型別說明符為關鍵字定義變數,具有自動儲存時期、程式碼塊作用域和空連結。不需要顯式地使用auto關鍵字來定義自動變數,編譯器不會自動進行初始化 

int main(void)
{
    auto int x; //不用顯式地使用auto關鍵字,如果在外部也同樣定義了x變數,這裡將會有內層定義覆蓋外部定義
}
int main(void)
{
    int x = 30;
    while(x++ < 33)
    {
        int x = 100; //重新定義x,覆蓋外部定義的x變數
        printf("x in while loop: %d\n", x);
    }
}
上面while例子中,每次迴圈結束後,在while中定義的x都會消失,然後用最初定義的x來作為while迴圈的條件判斷

暫存器變數:使用register儲存型別說明符為關鍵字定義變數,具有自動儲存時期、程式碼塊作用域和空連結,把變數存放在CPU的暫存器中,將會有更快的訪問和操作速度。因為暫存器變數是存放在一個暫存器而非記憶體中,所有無法獲得暫存器變數的地址。宣告暫存器變數僅僅是一個請求,而不是一個命令
,編譯器將會權衡是否作為暫存器變數,如果申請不成功,就會作為自動變數。
int main(void)
{
    register int x;
}
具有程式碼塊作用域的靜態變數:在程式碼塊中定義變數加上static儲存型別說明符,在程式碼塊作用域結束後,該變數不消失,具有靜態儲存時期、程式碼塊作用域和空連結。具有程式碼塊作用域的靜態變數只在編譯的時候初始化一次,如果不顯式地對靜態變數進行初始化,編譯器將會把它們初始化為0
while(x < 3)
{
    static int x = 1; //只在編譯的時候初始化為1,在進行後面的迴圈的時候,將跳過這一步
    printf("%d", x++);
}
void static_fun(static int x); //不能用static變數來做函式引數
具有外部連結的靜態變數:使用extern儲存型別說明符為關鍵字定義變數,具有靜態儲存時期、檔案作用域和外部連結,可以在多個檔案中使用該變數。這裡看一下變數定義和變數宣告的區別,關鍵字extern的存在標誌一個引用宣告,而非定義宣告
int x = 1; //變數的定義
void main(void)
{
    extern int x; //這裡只是宣告變數,不是對變數的定義,說明可以使用外部定義的變數
}

具有內部連結的靜態變數:使用static儲存型別說明符為關鍵字定義變數,具有靜態儲存時期、檔案作用域和內部連結,只可以在本檔案中宣告之後的任何地方使用該變數。

補充:函式儲存型別

函式同樣也具有儲存型別,函式預設情況下是外部的

int fun1();
static int fun2();
extern fun3();

函式fun1()和fun3()可以被程式中的其他檔案中的函式呼叫,而fun2()函式不行,只能在定義該函式的檔案裡被呼叫。