上文說到了C語言自動(dòng)變量的幾種類型,這里就說一下c語言外部鏈接的靜態(tài)變量的類型。
外部鏈接的靜態(tài)變量具有文件作用域、外部鏈接和靜態(tài)存儲(chǔ)期。該類別有時(shí)稱為外部存儲(chǔ)類別(external storage class),屬于該類別的變量稱為外部變量(external variable)。把變量的定義性聲明(defining declaration)放在所有函數(shù)的外面便創(chuàng)建了外部變量。
當(dāng)然,為了指出該函數(shù)使用了外部變量,可以在函數(shù)中用關(guān)鍵字extern
再次聲明。如果一個(gè)源代碼文件使用的外部變量定義在另一個(gè)源代碼文件中,則必須用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í)(這是可選的聲明)不用指明數(shù)組大小,因?yàn)榈?次聲明已經(jīng)提供了數(shù)組大小信息。main()
中的兩條extern
聲明完全可以省略,因?yàn)橥獠孔兞烤哂形募饔糜?,所?code>Errupt和Up
從聲明處到文件結(jié)尾都可見。它們出現(xiàn)在那里,僅為了說明main()
函數(shù)要使用這兩個(gè)變量。如果省略掉函數(shù)中的extern
關(guān)鍵字,相當(dāng)于創(chuàng)建了一個(gè)自動(dòng)變量。去掉下面聲明中的extern
:
extern int Errupt;
便成為:
int Errupt;
這使得編譯器在main()
中創(chuàng)建了一個(gè)名為Errupt
的自動(dòng)變量。它是一個(gè)獨(dú)立的局部變量,與原來的外部變量Errupt
不同。該局部變量?jī)Hmain()
中可見,但是外部變量Errupt
對(duì)于該文件的其他函數(shù)(如next())也可見。簡(jiǎn)而言之,在執(zhí)行塊中的語句時(shí),塊作用域中的變量將“隱藏”文件作用域中的同名變量。如果不得已要使用與外部變量同名的局部變量,可以在局部變量的聲明中使用auto
存儲(chǔ)類別說明符明確表達(dá)這種意圖。外部變量具有靜態(tài)存儲(chǔ)期。因此,無論程序執(zhí)行到main()
、next()
還是其他函數(shù),數(shù)組Up
及其值都一直存在。下面3個(gè)示例演示了外部和自動(dòng)變量的一些使用情況。示例1中有一個(gè)外部變量Hocus
。該變量對(duì)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中有一個(gè)外部變量Hocus
,對(duì)兩個(gè)函數(shù)均可見。這次,在默認(rèn)情況下對(duì)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個(gè)獨(dú)立的變量。main()
中的Hocus
變量默認(rèn)是自動(dòng)變量,屬于main()
私有。magic()
中的Hocus
變量被顯式聲明為自動(dòng),只有magic()
可用。外部變量Hocus
對(duì)main()
和magic()
均不可見,但是對(duì)該文件中未創(chuàng)建局部Hocus
變量的其他函數(shù)可見。最后,Pocus
是外部變量,magic()可見
,但是main()
不可見,因?yàn)?code>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個(gè)示例演示了外部變量的作用域是:從聲明處到文件結(jié)尾。除此之外,還說明了外部變量的生命期。外部變量Hocus
和Pocus
在程序運(yùn)行中一直存在,因?yàn)樗鼈儾皇芟抻谌魏魏瘮?shù),不會(huì)在某個(gè)函數(shù)返回后就消失。
初始化外部變量
外部變量和自動(dòng)變量類似,也可以被顯式初始化。與自動(dòng)變量不同的是,如果未初始化外部變量,它們會(huì)被自動(dòng)初始化為0。這一原則也適用于外部定義的數(shù)組元素。與自動(dòng)變量的情況不同,只能使用常量表達(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
(只要不是變長(zhǎng)數(shù)組,sizeof
表達(dá)式可被視為常量表達(dá)式。)
使用外部變量
下面來看一個(gè)使用外部變量的示例。假設(shè)有兩個(gè)函數(shù)main()
和critic()
,它們都要訪問變量units
??梢园?code>units聲明在這兩個(gè)函數(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個(gè)值的。當(dāng)while
循環(huán)結(jié)束時(shí),main()
也知道units
的新值。所以main()
函數(shù)和critic()
都可以通過標(biāo)識(shí)符units
訪問相同的變量。用C
的術(shù)語來描述是,units
具有文件作用域、外部鏈接和靜態(tài)存儲(chǔ)期。
把units
定義在所有函數(shù)定義外面(即外部),units
便是一個(gè)外部變量,對(duì)units
定義下面的所有函數(shù)均可見。因此,critics()
可以直接使用units
變量。
類似地,main()
也可直接訪問units
。但是,main()
中確實(shí)有如下聲明:
extern int units;
本例中,以上聲明主要是為了指出該函數(shù)要使用這個(gè)外部變量。存儲(chǔ)類別說明符extern
告訴編譯器,該函數(shù)中任何使用units
的地方都引用同一個(gè)定義在函數(shù)外部的變量。再次強(qiáng)調(diào),main()
和critic()
使用的都是外部定義的units
。
外部名稱
C99
和C11
標(biāo)準(zhǔn)都要求編譯器識(shí)別局部標(biāo)識(shí)符的前63個(gè)字符和外部標(biāo)識(shí)符的前31個(gè)字符。這修訂了以前的標(biāo)準(zhǔn),即編譯器識(shí)別局部標(biāo)識(shí)符前31個(gè)字符和外部標(biāo)識(shí)符前6個(gè)字符。你所用的編譯器可能還執(zhí)行以前的規(guī)則。外部變量名比局部變量名的規(guī)則嚴(yán)格,是因?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ù)留了存儲(chǔ)空間,該聲明構(gòu)成了變量的定義。第2次聲明只告訴編譯器使用之前已創(chuàng)建的tern
變量,所以這不是定義。第1次聲明被稱為定義式聲明(defining declaration),第2次聲明被稱為引用式聲明(referencing declaration)。關(guān)鍵字extern
表明該聲明不是定義,因?yàn)樗甘揪幾g器去別處查詢其定義。
假設(shè)這樣寫:
extern int tern;
int main(void)
{
編譯器會(huì)假設(shè)tern
實(shí)際的定義在該程序的別處,也許在別的文件中。該聲明并不會(huì)引起分配存儲(chǔ)空間。因此,不要用關(guān)鍵字extern
創(chuàng)建外部定義,只用它來引用現(xiàn)有的外部定義。
外部變量只能初始化一次,且必須在定義該變量時(shí)進(jìn)行。假設(shè)有下面的代碼:
// file one.c
char permis = 'N';
...
// file two.c
extern char permis = 'Y'; /* error */
file_two
中的聲明是錯(cuò)誤的,因?yàn)?code>file_one.c中的定義式聲明已經(jīng)創(chuàng)建并初始化了permis
。
以上就是關(guān)于C語言外部鏈接的靜態(tài)變量類型的說明,對(duì)C語言有興趣的同學(xué)可以看一下教程