上文說到了C語言自動變量的幾種類型,這里就說一下c語言外部鏈接的靜態(tài)變量的類型。
外部鏈接的靜態(tài)變量具有文件作用域、外部鏈接和靜態(tài)存儲期。該類別有時稱為外部存儲類別(external storage class),屬于該類別的變量稱為外部變量(external variable)。把變量的定義性聲明(defining declaration)放在所有函數(shù)的外面便創(chuàng)建了外部變量。
當(dāng)然,為了指出該函數(shù)使用了外部變量,可以在函數(shù)中用關(guān)鍵字extern
再次聲明。如果一個源代碼文件使用的外部變量定義在另一個源代碼文件中,則必須用extern
在該文件中聲明該變量。如下所示:
int Errupt; /* externally defined variable */
double Up[100]; /* externally defined array */
extern char Coal; /* mandatory declaration if */
/* Coal defined in another file */
void next(void);
int main(void)
{
extern int Errupt; /* optional declaration */
extern double Up[]; /* optional declaration */
...
}
void next(void)
{
...
}
注意,在main()
中聲明Up
數(shù)組時(這是可選的聲明)不用指明數(shù)組大小,因為第1次聲明已經(jīng)提供了數(shù)組大小信息。main()
中的兩條extern
聲明完全可以省略,因為外部變量具有文件作用域,所以Errupt
和Up
從聲明處到文件結(jié)尾都可見。它們出現(xiàn)在那里,僅為了說明main()
函數(shù)要使用這兩個變量。如果省略掉函數(shù)中的extern
關(guān)鍵字,相當(dāng)于創(chuàng)建了一個自動變量。去掉下面聲明中的extern
:
extern int Errupt;
便成為:
int Errupt;
這使得編譯器在main()
中創(chuàng)建了一個名為Errupt
的自動變量。它是一個獨立的局部變量,與原來的外部變量Errupt
不同。該局部變量僅main()
中可見,但是外部變量Errupt
對于該文件的其他函數(shù)(如next())也可見。簡而言之,在執(zhí)行塊中的語句時,塊作用域中的變量將“隱藏”文件作用域中的同名變量。如果不得已要使用與外部變量同名的局部變量,可以在局部變量的聲明中使用auto
存儲類別說明符明確表達(dá)這種意圖。外部變量具有靜態(tài)存儲期。因此,無論程序執(zhí)行到main()
、next()
還是其他函數(shù),數(shù)組Up
及其值都一直存在。下面3個示例演示了外部和自動變量的一些使用情況。示例1中有一個外部變量Hocus
。該變量對main()
和magic()
均可見。
/* Example 1 */
int Hocus;
int magic();
int main(void)
{
extern int Hocus; // Hocus declared external
...
}
int magic()
{
extern int Hocus; // same Hocus as above
...
}
示例2中有一個外部變量Hocus
,對兩個函數(shù)均可見。這次,在默認(rèn)情況下對magic()
可見。
/* Example 2 */
int Hocus;
int magic();
int main(void)
{
extern int Hocus; // Hocus declared external
...
}
int magic()
{
// Hocus not declared but is known
...
}
在示例3中,創(chuàng)建了4個獨立的變量。main()
中的Hocus
變量默認(rèn)是自動變量,屬于main()
私有。magic()
中的Hocus
變量被顯式聲明為自動,只有magic()
可用。外部變量Hocus
對main()
和magic()
均不可見,但是對該文件中未創(chuàng)建局部Hocus
變量的其他函數(shù)可見。最后,Pocus
是外部變量,magic()可見
,但是main()
不可見,因為Pocus
被聲明在main()
后面。
/* Example 3 */
int Hocus;
int magic();
int main(void)
{
int Hocus; // Hocus declared, is auto by default
...
}
int Pocus;
int magic()
{
auto int Hocus; // local Hocus declared automatic
...
}
這3個示例演示了外部變量的作用域是:從聲明處到文件結(jié)尾。除此之外,還說明了外部變量的生命期。外部變量Hocus
和Pocus
在程序運行中一直存在,因為它們不受限于任何函數(shù),不會在某個函數(shù)返回后就消失。
初始化外部變量
外部變量和自動變量類似,也可以被顯式初始化。與自動變量不同的是,如果未初始化外部變量,它們會被自動初始化為0。這一原則也適用于外部定義的數(shù)組元素。與自動變量的情況不同,只能使用常量表達(dá)式初始化文件作用域變量:
int x = 10; // ok, 10 is constant
int y = 3 + 20; // ok, a constant expression
size_t z = sizeof(int); // ok, a constant expression
int x2 = 2 * x; // not ok, x is a variable
(只要不是變長數(shù)組,sizeof
表達(dá)式可被視為常量表達(dá)式。)
使用外部變量
下面來看一個使用外部變量的示例。假設(shè)有兩個函數(shù)main()
和critic()
,它們都要訪問變量units
??梢园?code>units聲明在這兩個函數(shù)的上面,如程序清單12.4所示(注意:該例的目的是演示外部變量的工作原理,并非它的典型用法)。
/* global.c -- uses an external variable */
#include <stdio.h>
int units = 0; /* an external variable */
void critic(void);
int main(void)
{
extern int units; /* an optional redeclaration */
printf("How many pounds to a firkin of butter?n");
scanf("%d", &units);
while ( units != 56)
critic();
printf("You must have looked it up!n");
return 0;
}
void critic(void)
{
/* optional redeclaration omitted */
printf("No luck, my friend. Try again.n");
scanf("%d", &units);
}
下面是該程序的輸出示例:
How many pounds to a firkin of butter?
14
No luck, my friend. Try again.
56
You must have looked it up!
(We did.)
注意,critic()
是如何讀取units
的第2個值的。當(dāng)while
循環(huán)結(jié)束時,main()
也知道units
的新值。所以main()
函數(shù)和critic()
都可以通過標(biāo)識符units
訪問相同的變量。用C
的術(shù)語來描述是,units
具有文件作用域、外部鏈接和靜態(tài)存儲期。
把units
定義在所有函數(shù)定義外面(即外部),units
便是一個外部變量,對units
定義下面的所有函數(shù)均可見。因此,critics()
可以直接使用units
變量。
類似地,main()
也可直接訪問units
。但是,main()
中確實有如下聲明:
extern int units;
本例中,以上聲明主要是為了指出該函數(shù)要使用這個外部變量。存儲類別說明符extern
告訴編譯器,該函數(shù)中任何使用units
的地方都引用同一個定義在函數(shù)外部的變量。再次強(qiáng)調(diào),main()
和critic()
使用的都是外部定義的units
。
外部名稱
C99
和C11
標(biāo)準(zhǔn)都要求編譯器識別局部標(biāo)識符的前63個字符和外部標(biāo)識符的前31個字符。這修訂了以前的標(biāo)準(zhǔn),即編譯器識別局部標(biāo)識符前31個字符和外部標(biāo)識符前6個字符。你所用的編譯器可能還執(zhí)行以前的規(guī)則。外部變量名比局部變量名的規(guī)則嚴(yán)格,是因為外部變量名還要遵循局部環(huán)境規(guī)則,所受的限制更多。
定義和聲明
下面進(jìn)一步介紹定義變量和聲明變量的區(qū)別??紤]下面的例子:
int tern = 1; /* tern defined */
main()
{
external int tern; /* use a tern defined elsewhere */
這里,tern
被聲明了兩次。第1次聲明為變量預(yù)留了存儲空間,該聲明構(gòu)成了變量的定義。第2次聲明只告訴編譯器使用之前已創(chuàng)建的tern
變量,所以這不是定義。第1次聲明被稱為定義式聲明(defining declaration),第2次聲明被稱為引用式聲明(referencing declaration)。關(guān)鍵字extern
表明該聲明不是定義,因為它指示編譯器去別處查詢其定義。
假設(shè)這樣寫:
extern int tern;
int main(void)
{
編譯器會假設(shè)tern
實際的定義在該程序的別處,也許在別的文件中。該聲明并不會引起分配存儲空間。因此,不要用關(guān)鍵字extern
創(chuàng)建外部定義,只用它來引用現(xiàn)有的外部定義。
外部變量只能初始化一次,且必須在定義該變量時進(jìn)行。假設(shè)有下面的代碼:
// file one.c
char permis = 'N';
...
// file two.c
extern char permis = 'Y'; /* error */
file_two
中的聲明是錯誤的,因為file_one.c
中的定義式聲明已經(jīng)創(chuàng)建并初始化了permis
。
以上就是關(guān)于C語言外部鏈接的靜態(tài)變量類型的說明,對C語言有興趣的同學(xué)可以看一下教程