2.鏈接
一個C變量具有下列鏈接之一:
外部鏈接 (external linkage)
內部鏈接 (internal linkage)
空鏈接 (no linkage)
具有代碼塊作用域或者函數原型作用域的變量具有空鏈接,意味著它們是由其定義所在的代碼塊或函數原型所私有的。
具有文件作用域的變量可能有內部或者外部鏈接。
一個具有外部鏈接的變量可以在一個多文件程序的任何地方使用。
一個具有內部鏈接的變量可以在一個文件的任何地方使用。
那怎樣知道一個文件作用域變量具有內部鏈接還是外部鏈接?
你可以看看在外部定義中是否使用了存儲類說明符static:
int giants = 5;//文件作用域,外部鏈接
static int dodgers = 3;//文件作用域,內部鏈接
int main ()
{
……
}
和該文件屬于同一程序的其他文件可以使用變量giants。
變量dodgers是該文件私有的,但是可以被該文件中的任一函數使用。
2.存儲時期
一個C變量有兩種存儲時期之一:
靜態存儲時期(static storage duration)和自動存儲時期(automatic storage duration)。
如果一個變量具有靜態存儲時期,它在程序執行期間將一直存在。
具有文件作用域的變量具有靜態存儲時期。
注意對于具有文件作用域的變量,關鍵字static表示鏈接類型,并非存儲時期。
因為所有的文件作用域變量,無論它具有內部鏈接,還是具有外部鏈接,都具有靜態存儲時期。
具有代碼塊作用域的變量一般情況下具有自動存儲時期。
當程序進入定義這些變量的代碼塊時,將為這些變量分配內存。
當推出這個代碼塊時,內存將被釋放。
這樣,在一個函數調用結束后,它的變量所占用的內存空間可以用來存儲下一個被調用函數的變量。
到現在我們所使用的局部變量都屬于自動類型。
void bore (int number)
{
int index;
for (index = 0; index < number; index++)
{
puts ("They don't make them the way they used to.\n");
return 0;
}
}
總論:c使用作用域、鏈接和存儲時期來定義5中存儲類。
自動,寄存器、具有代碼塊作用域的靜態、具有外部鏈接的靜態、具有內部鏈接的靜態
1.自動變量
自動變量具有自動存儲時期、代碼塊作用域和空鏈接。
默認情況下,在代碼塊或函數的頭部定義的任意變量都屬于自動存儲類。
你可以顯示的使用關鍵字auto來表明一個變量為自動變量,但我們一般不寫。
int main (void)
{
auto int plox;
}
int loop (int n)
{
int m; // m的作用域
scanf ("%d", &m);
{
int i; // m和i的作用域
for (i=m; i < n; i++)
{
puts ("i is local to a sub-block\n");
}
}
return m; // m的作用域, i已經消失
}
如果在內層代碼塊定義了一個具有和外層代碼塊便來那個同一名字的變量,將會怎樣?
(最好不要在你的代碼中這樣做)
這時內層代碼塊將使用在內層代碼塊中這個新定義的變量。
我們稱之為內層定義覆蓋(hide)了外部定義,只有當運行離開內層代碼塊是,外部變量才會重新恢復使用。
#include <stdio.h>
int main (void)
{
int x = 30;
printf ("x in outer block: %d\n", x);
{
int x = 77;
printf ("x in inner block: %d\n", x);
}
}
注意:
c99中規定,語句若為循環或者if語句的一部分,即使沒有使用{},也認為是一個代碼塊。
#include <stdio.h>
int main (void)
{
int n = 10;
printf ("Initially, n = %d\n", n);
for (int n = 1; n < 3; n++)
printf ("loop : n = %d\n", n);
printf ("Initially, n = %d\n", n);
return 0;
}
注意:
除非您顯式地初始化自動變量,否則它不會被自動初始化。
int main (void)
{
int repid;
int tents = 5;
}
repid的初值則是先前占用分配給它的空間的任意值。不要指望這個值是0。
2.寄存器變量
通常,變量存儲在計算機內存中。如果幸運,寄存器變量可以被存儲在CPU的寄存器中,這樣速度會更快。
在其它許多方面,它和自動變量是一樣的。
通過使用存儲類型說明符register可以聲明寄存器變量。
int main (void)
{
register int quick;
}
我們說如果幸運是因為聲明一個寄存器類變量僅僅是一個請求,而不是一條直接命令。
因為CPU寄存器往往很少,編譯器必須在可用寄存器的個數和可用高速內存的數量之間做權衡。
這種情況下,變量成為一個普通的自動變量。
但是,你不能對它使用地址運算符。
可以把一個形式參量請求為寄存器變量。
void macho (register int n)
3.具有代碼塊作用域的靜態變量
靜態變量像是一個不可變的變量。
但實際上,靜態指變量的的位置固定不動。
具有文件作用域的變量自動的具有靜態存儲時期。
也可以創建具有代碼塊作用域,兼具有靜態存儲的局部變量。
這些變量和自動變量具有相同的作用域,當包含這些變量的函數完成工作時,它們并不消失。
從一次函數調用到下一次調用,計算機都記錄著他們的值。
我們可以使用存儲類說明符static在代碼塊內聲明這些變量。
#include <stdio.h>
void trystat (void);
int main (void)
{
int count;
for (count = 1; count <= 3; count++)
{
printf ("Here comes iteration %d:\n", count);
trystat ();
}
return 0;
}
void trystat (void)
{
int fade = 1;
static int stay = 1;
printf ("fade = %d and stay = %d\n", fade++, stay++);
}
注意:
對函數參數不能使用static。
4.具有外部鏈接的靜態變量
具有外部鏈接的靜態變量具有文件作用域、外部鏈接和靜態存儲時期。
這一類型的變量成為外部變量 external variable。
把變量的定義聲明放在所有函數之外,即創建了一個外部變量。
為了使程序更加清晰,可以在使用外部變量的函數中通過使用extern關鍵字來再次聲明它。
如果變量是在別的文件中定義的,使用extern來聲明該變量就是必須的。
int Errupt; //外部定義的變量
double Up[100]; //外部聲明的數組
extern char Coal; //必須的聲明,因為Coal在其它文件中定義
void next (void);
int main (void)
{
extern int Errupt;//可選的聲明
extern double Up[];//可選的聲明
}
void next (void)
{
}
注意:
不同于自動變量,如果您不對外部變量進行初始化,他們將自動被賦初值0。
這一原則也適用于外部定義的數組。
5.具有內部靜態鏈接的靜態變量
通過使用存儲類說明符(注意不是靜態變量聲明符)static在所有函數的外部進行定義,前面已經說過該變量為整個文件私有
,這里不再討論。
int traveler = 1; //外部鏈接
static int stayhome = 1; //內部鏈接