在 C 語言中,static 關鍵字不僅可以用來修飾變數,還可以用來修飾函數。在使用 static 關鍵字修飾變數時,我們稱此變數為
靜態變數。
靜態變數的儲存方式與全域性變數一樣,都是靜態儲存方式。但這裡需要特別說明的是,靜態變數屬於靜態儲存方式,屬於靜態儲存方式的變數卻不一定就是靜態變數。例如,全域性變數雖然屬於靜態儲存方式,但並不是靜態變數,它必須由 static 加以定義後才能成為靜態全域性變數。
考慮到可能會有不少讀者對靜態變數作用不太清楚,本節就來詳細討論一下它的主要作用。
隱藏與隔離的作用
上面已經闡述過,全域性變數雖然屬於靜態儲存方式,但並不是靜態變數。全域性變數的作用域是整個源程式,當一個源程式由多個原始檔組成時,全域性變數在各個原始檔中都是有效的。
如果我們希望全域性變數僅限於在本原始檔中使用,在其他原始檔中不能參照,也就是說限制其作用域只在定義該變數的原始檔內有效,而在同一源程式的其他原始檔中不能使用。這時,就可以通過在全域性變數之前加上關鍵字 static 來實現,使全域性變數被定義成為一個靜態全域性變數。這樣就可以避免在其他原始檔中引起的錯誤。也就起到了對其他原始檔進行隱藏與隔離錯誤的作用,有利於模組化程式設計。
保持變數內容的永續性
有時候,我們希望函數中區域性變數的值在函數呼叫結束之後不會消失,而仍然保留其原值。即它所佔用的儲存單元不釋放,在下一次呼叫該函數時,其區域性變數的值仍然存在,也就是上一次函數呼叫結束時的值。這時候,我們就應該將該區域性變數用關鍵字 static 宣告為“靜態區域性變數”。
當將區域性變數宣告為靜態區域性變數的時候,也就改變了區域性變數的儲存位置,即從原來的棧中存放改為靜態儲存區存放。這讓它看起來很像全域性變數,其實靜態區域性變數與全域性變數的主要區別就在於可見性,靜態區域性變數只在其被宣告的程式碼塊中是可見的。
對某些必須在呼叫之間保持區域性變數的值的子程式而言,靜態區域性變數是特別重要的。如果沒有靜態區域性變數,則必須在這類函數中使用全域性變數,由此也就開啟了引入副作用的大門。使用靜態區域性變數最好的範例就是實現統計次數的功能,如下面範例所示。
#include <stdio.h>
void count();
int main(void)
{
int i=0;
for (i = 0;i <= 5;i++)
{
count();
}
return 0;
}
void count()
{
/*宣告一個靜態區域性變數*/
static num = 0;
num++;
printf("%dn",num);
}
在該程式碼中,我們通過在 count() 函數裡宣告一個靜態區域性變數 num 來作為計數器。因為靜態區域性變數是在編譯時賦初值的,且只賦初值一次,在程式執行時它已有初值。以後在每次呼叫函數時就不再重新賦初值,而是保留上次函數呼叫結束時的值。這樣,count() 函數每次被呼叫的時候,靜態區域性變數 num 就會保持上一次呼叫的值,然後再執行自增運算,這樣就實現了計數功能。同時,它又避免了使用全域性變數。
通過上面的範例,我們可以得出靜態區域性變數一般的使用場景,如下所示:
-
需要保留函數上一次呼叫結束時的值。
-
如果初始化後,變數只會被參照而不會改變其值,則這時用靜態區域性變數比較方便,以免每次呼叫時重新賦值。
預設初始化為 0
在靜態資料區,記憶體中所有的位元組預設值都是 0x00。靜態變數與全域性變數也一樣,它們都儲存在靜態資料區中,因此其變數的值預設也為 0。演示範例如下所示。
#include <stdio.h>
static int g_x;
int g_y;
int main(void)
{
static int x;
printf("g_x:%dng_y:%dnx:%d",g_x,g_y,x);
return 0;
}
執行結果為:
g_x:0
g_y:0
x:0