標籤:c static 字串常量
一、範圍、連結屬性以及儲存類型:
1. 範圍:常見範圍有代碼塊、檔案、函數以及原型範圍(只適用於在函數原型中聲明的參數名)。
2. 連結屬性:
a) 連結可以將多個目標檔案連結產生最後的目標檔案。連結屬性則是決定如何處理在不同檔案中出現的標識符。
b) 連結屬性總共有三種:external(外部)、internal(內部)以及none(無)。預設情況下標識符一般是外部或者無屬性,但是,通過static關鍵字,則可以改變標識符的屬性,將外部屬性轉變成內部屬性,一般我們所說的內外連結屬性其實也是相對於檔案範圍而言的。
預設情況下,中b,c,f的連結屬性是外部的,其它的則是無連結屬性,f是一個外部函數,
【補充】extern關鍵字則可以指定某個標識符是來自於外部源檔案,即可以將原來的內部或者無連結屬性改成外部連結屬性。我們可以考慮一種比較複雜的情況,那就是當內外連結屬性範圍同一個標識符時,標識符的連結屬性該如何取捨?
如,當extern關鍵字作用於標識符i並試圖改變其連結屬性時,此時會失效,即它不會更改前面已有的連結屬性。
c) 儲存類型:
i. 變數的儲存類型是指儲存變數值的記憶體類型,它覺得了變數何時建立、何時銷毀以及它的值可以儲存多久。大類上講,有兩個地方可以儲存變數值:普通記憶體以及硬體寄存器。根據下面的記憶體劃分圖,可儲存變數的地區主要有:靜態區、堆區以及棧區。
【注意】存在靜態區的變數主要是全域變數以及被static關鍵字轉換的自動變數,值得注意的是,常量也是存放在靜態區。我們可以特意分析下代碼塊內的自動變數被static修飾的情況:經過static修飾的自動變數,只是儲存類型發生了變化,並不影響它的範圍,只能在代碼內部訪問。另外它在整個程式的執行過程中一直存在,並不會重新初始化!
void count_test(){ static int count = 0; count++; printf("count is %d\n", count);}
如上面這段代碼,內建一個靜態變數,可以統計函數被調用的次數。
【擴充】被static修飾的自動變數的賦值問題:
根據C99標準:All theexpressions in an initializer for an object that has static storage durationshall be constant expressions or string literals. 因此,對給利用static關鍵字改變儲存屬性的變數賦值時,一定只能是常量運算式或者字串常量。否則會出現“initializer element is not constant”的編譯錯誤。
ii 寄存器變數
關鍵字register可以用於自動變數的聲明,提示這個變數是儲存在寄存器中,而不是記憶體中,對比記憶體,寄存器的變數訪問效果更優。一般來講,可以將使用頻率最高的變數存在於寄存器中。
二、字串常量:
針對字串常量,主要在於理解,如儲存位置,以及一些進階用法。根據前面的儲存類型可知,字串常量的實質是一個指標常量,也應該是儲存在靜態區的。
char *TEST_pointer_constant(){ //stack char detailFaultStr[10] = {0}; //locao array is tmp and stored in stack. sprintf(detailFaultStr, "%s", "asd"); //static data area char *detailFaultStr = "abc"; return detailFaultStr;}int main(int argc, char **argv){ char *tmp = TEST_pointer_constant(); printf("%s.\n", tmp); return 0;}
上面這個例子從側面反映了指標所指向的記憶體所儲存的位置不同,而出現不同的結果,第一種情況返回的是一個數組名,其所指向的記憶體時存在棧中,其範圍只存在與整個函數中,而第二種情況則是指向的是靜態區(字串常量),它的範圍是整個程式運行期。另外通過這個例子,可以看出我們通常所理解的不能將函數內的局部變數作為返回值返回,也不是所有情況下都必須遵守。
下面這個例子展示了常量運算式作為指標常量的靈活用法:
void TEST_pointer_constant(){ printf("%s.\n", "xyz"); //xyz printf("%s.\n", "xyz"+1); //yz printf("%c.\n", *"xyz"); //x printf("%c.\n", "xyz"[1]); //y printf("%c.\n", *("xyz"+2)); //z putchar("0123456789ABCDEF"[11%16]); //can use to convert hexadecimal //B}