C和指針 3.9做用域、存儲類型示例

 1 int             a = 5;
 2 extern int      b;
 3 static int      c;
 4 
 5 int d( int e )
 6 {
 7     int             f = 15;
 8     register int    b;
 9     static int      g = 20;
10     extern int      a;
11     ...
12     {
13         int         e;
14         int         a;
15         extern int  h;
16         ...
17     }
18     ...
19     {
20         int         x;
21         int         e;
22         ...
23     }
24     ...
25 }
26 static int i()
27 {
28     ...
29 }
30 ...

  屬於文件做用域的聲明在缺省狀況下爲external連接屬性,因此第1行的a的連接屬性爲external。函數

  若是b的定義在其餘地方,第2行的external關鍵字在技術上並不是必需,但在風格上倒是圓環這個關鍵字爲好。spa

  第3行的static關鍵字修改了c的缺省連接屬性,把它改成爲internal。code

  聲明瞭變量a和b(具備external連接屬性)的其餘源文件在使用這兩個變量時實際所訪問的是聲明於此處的兩個變量。可是變量c只能由這個源文件訪問,由於它具備internal連接屬性。blog

  變量a、b、c的存儲類型爲靜態,表示它們並非存儲於堆棧中。所以,這些變量在程序執行以前建立,並一塊兒保持它們的值,直到程序結束。它程序開始執行時,這是a將初始化爲5。遞歸

  這些變量的做用域一直延伸到這個源文件結束爲止,但第7行和第13行聲明的局部變量a和b在那部分程序中將隱藏同名的靜態變量。所以,這3個變量的做用域爲:生命週期

  a 第1到12行, 第17到29行內存

  b 第2到第6行, 第25到29行作用域

  c 第3到第29行原型

  第4行聲明瞭2個標識符。d的做用域從第4行直到文件結束。函數d的定義對於這個源文件中任何之後想要調用 它的函數而言直到了函數原型的做用。做爲函數名,d在缺省狀況下具備external連接屬性,因此其餘源文件只有在文件上存在d的原型,就能夠調用d。若是咱們將函數聲明爲static,就能夠把它的連接屬性從external爲改成internal,但這樣作將使其餘源文件不能訪問這個函數。對於函數而言,存儲類型並非問題,由於代碼老是存儲於靜態內存中。編譯器

  參數e不具備連接屬性,因此咱們只能從函數內部經過名字訪問它。它具備自動存儲類型,因此它在函數被調用時被創到建,當函數返回時消失。因爲局部變量衝突,它的做用域限於第6到11行,第17到19行以及第23到24行。

  第6到8行聲明局部變量,因此它們的做用域到函數結束爲止。它們不具備連接屬性,因此它們不能在函數的外部經過名字訪問(這是它們稱爲局部變量的緣由)。f的存儲類型是自動,當函數每次被調用時,它經過隱匿賦值被初始化爲。b的存儲類型是寄存器類型,因此它的初始值是垃圾。g的存儲類型是靜態,因此它在程序的整個執行過程當中一直存在。當程序開始執行時,它被初始化爲20。當函數每次被調用時,它並不會被從新初始化。

  第9行的聲明並不須要。這個代碼塊位於第1行聲明的做用域以內。

  第12 和 13行爲代碼塊聲明局部變量。它們都具備自動存儲類型,不具備連接屬性,它們的做用域延伸到第16行。這些變量和先前聲明的a和e不一樣,並且因爲名字衝突,在這個代碼塊中,之前聲明的同名變量是不能被訪問的。

  第14行使全局變量h在這個代碼塊內能夠被訪問。它具備external連接屬性,存儲於靜態內存中。這是惟一一個必須使用external關鍵字的聲明,若是沒有它,h將變成另外一個局部變量。

  第19行和20行用於建立局部變量(自動、無連接屬性、做用域限於本代碼塊)。這個e和參數e是不一樣的變量,它和第12行聲明的e也不相同。在這個代碼塊中,從第11行到18行並沒有嵌套,因此編譯器可使用相同的內存來存儲兩個代碼塊中不一樣的變量e。若是你想讓這兩個代碼塊的的有表示同一個變量,那麼你就不該該把它聲明爲局部變量。

  最後,第25行聲明瞭函數i,它具備靜態連接屬性。靜態連接屬性能夠它防止它被這個源文件以外的任何函數調用。事實上,其餘的源文件也可能聲明它本身的函數i,它與這個源文件的i是不一樣的函數。i的做用域從它聲明的位置直到這個源文件結束。函數d不能夠調用函數i,由於d以前不存在i的原型。

 

  具備external連接屬性的實體在其餘語言的術語裏稱爲全局實體,因此源文件中的全部函數都可以被訪問它。只要變量並不是聲明於代碼塊或函數定義內部,它在缺省狀況下的連接屬性即爲external。若是一個變量聲明於代碼塊內部,在它前面添加external關鍵字將使它所引用的是全局變量而非局部變量。

  具備external連接屬性的實體老是具備靜態存儲類型。全局變量在程序開始執行前建立,並在程序整個執行過程當中始終存在。從屬於函數的局部變量在函數開始執行時建立,在函數執行完畢後銷燬,但用於執行函數的機器指令在程序的生命週期內一直存在。

  局部變量由函數內部使用,不能被其餘函數經過名字引用。它在缺省狀況下的存儲類型爲自動,這是基於兩個緣由:其一,當這些變量須要時才爲它們分配存儲,這樣能夠減小內存的總需求量。其二,在堆棧上爲它們分配存在可能有效地實現遞歸。若是你以爲讓變量的值在函數的屢次調用中始終保持原先的值很是重要的話,你能夠修改它的存儲類型,把它從自動變量改成靜態變量。

做用域、連接屬性和存儲類型總結
變量類型 聲明的位置  是否存於堆棧 做用域 若是聲明爲static
全局 全部代碼塊以外 從聲明處到文件尾 不容許從其餘源文件訪問
局部 代碼塊起始處 整個代碼塊 變量不存儲於堆棧中,它的值在程序整個執行期一塊兒保持
形式參數 函數頭部 整個函數 不容許
相關文章
相關標籤/搜索