暫存變數vs.常駐變數
由於函式的可重用性,在同一個程式中所用到的不同函式,可能會是由不同的程式設計師,在不同時期所完成的作品。 因此,在同一個程式中的不同函式內的不同變數,被命名為相同名稱的機會很大。為解決同名問題,對於變數名稱的可視區域(Scope),應該有所限制,才能避免某一函式內部變數內容不經意被另外一個函式在寫入相同名稱的其他變數時誤寫。
原本一段程式碼內的變數基本上只有一份,然而當這段函式被獨立包裝成函式之後,為了避免呼叫同一個函式執行相同程式碼時會交互影響,需要區隔不同次呼叫函式時函式內部變數,然而若是同一個函式每一次被呼叫都產生一份新變數,則有可能在函式被呼叫多次之後,總變數佔用記憶體會超出電腦的記憶體容量。 因此一般狀況,函式內的變數記憶體,會在它被呼叫時,才從記憶體中動態取得(Dynamic allocate),並於結束函式執行之後,將動態取得的記憶體釋放(Release),而變數內容則隨記憶體釋放而消失,因為內容會消失,所以這些在函式內定義出來的變數是暫存變數。 相較於函式內定義的暫存變數,若是變數被定義在所有函式之外,則這些變數會在程式執行前就被定義在電腦記憶體上,而且會常駐在該位址上不會消失,我們稱之為常駐(static)變數。
區域變數 與 廣域變數 (Local Variables vs. Global Variables)
在函式內部定義的變數,除了在離開函式時會消失的特徵之外,它的可視範圍僅限於函式內部,所以又被稱為是區域變數(Local Variables)。
不在函式內部定義的變數,基本上從檔案內定義它的那一行指令之後的所有函式,都會知道它的存在並且可以存取它,他的可視範圍廣及之後的所有函式,所以又稱為廣域變數(Global Variables)。
如果一個原始程式檔案,xxx.c 需要用到某一個廣域變數,這個廣域變數是來自於另一個檔案的定義,則我們必須用extern的關鍵字,告訴編譯器,這個變數是來自於檔案外部。
也就是說函式只能夠看到自己內部定義的區域變數,在同一檔案內先前定義過的廣域變數,以及在檔案內巳經在先前以extern宣告過來自於其它檔案的廣域變數。
Static限制碼
static的限制碼,最基本涵意就是靜態,有不變的意思。若用它來限制函式內的變數時就有不讓它的內容消失不見的意思,會有由暫存變數變成永久變數的效果。 若用在來限制C語言檔的定義在所有函式外面的廣域永久變數時,就有不讓其他放在不同檔案的函式改變這個變數的意思,會有由廣域變數限制成同一個C檔案之內才可讀寫的區域限制變數的效果。
在函式內部定義的區域變數,雖然具有不被其它函式干擾的好處,但因為他同時也是暫存變數,在結束函式後就會消失。若實際應用上需要永久記住的變數,必須在所有函式外部定義出來,它的內容才不會有被清除的可能,但因為他是廣域變數可以讓所有同檔案內的函式讀寫,因此也就存在被誤寫的機會。 在高階的程式設計上,可能會出現,一方面希望函式內的變數內容在結束離開後不被清除,一方面又希望避免其它函式誤寫到這些內容。針對這類需求,只要在函式內部定義的區域變數之前加一個static的限制碼,(此時Staic的意思是常存常駐),讓該區域變數轉變成常駐變數。這種常駐區域變數在一個函式執行完畢後變數不會釋放記憶體,內容不會消失直到下一次呼叫再執行時,仍能使用上一次呼叫執行之後留下來的值。
例如疊代平均函式
int rec_avg(int i){
static int sum=0, count=0;
int avr=0;
sum=sum+i;
count++;
avr=sum/count;
return(avr);
}
上面的函式sum,count 與為永久區域變數,執行結束不會忘記,下次執行時會重用上次的執行的等式左邊結果sum=sum+i,來替代同一運算式第二次執行右邊的原值sum=sum+i重覆相同等式的運算,這種方式的運算被稱為疊代運算。
而 avr則是一般暫時區域變數,每次被呼叫時會重新產生一個新變數並初始為0,在離開函式時,就釋放記憶體。
利用extern關鍵字,某一個檔案可以宣告他所使用到的某一個變數是來自於其他檔案,以擴增在另外一個檔案內廣域變數的視域範圍可達到本檔案範圍。但是這個擴增可視範圍的動作,對於原來定義被擴增範圍變數的檔案而言,郤是被動的。 這個擴增範圍動作對原檔案而言也同時增加了受到未來不明函式寫入不當值干擾的風險。
如果一個檔案內,有些廣域變數對於外檔函式的不當改寫很敏感時,則必須要限制這些廣域變數只允許本檔案內的函式讀寫,禁止外檔函式以extern 宣告為其他檔案也能讀寫。static限制碼,也可以用來限制廣域變數,令其可視範圍受限在本檔案內,不被其他檔案的extern 宣告影響。
同樣一個疊代平均函式,固然可以利用static限制把區域暫時變數變成永久區域變數來讓這個變數得以疊代更新。另外也可以利用static限制,把可能被擴大可視範圍的永久廣域變數限制為比較安全的同檔案內可視的廣域變數。
例如疊代平均函式
與前一個範例比較 static int sum=0, count=0;被搬到函式的外面,使得 sum, count成為永久廣域變數。又因為這一個函式是獨立定義在一個小而獨立的檔案之內,因為在這個檔案內sum, count己被用 static 限制 為檔案內可視,故其他呼叫這個函式的檔案,將無法用extern 擴充這兩個變數的可視範圍,也就無法讀寫干擾這兩個變數。