C語(yǔ)言中的static 詳細(xì)分析

引用自Cobing Liu
C語(yǔ)言代碼是以文件為單位來(lái)組織的舔痕,在一個(gè)源程序的所有源文件中,一個(gè)外部變量(注意不是局部變量)或者函數(shù)只能在一個(gè)源程序中定義一次宋渔,如果有重復(fù)定義的話編譯器就會(huì)報(bào)錯(cuò)彤委。伴隨著不同源文件變量和函數(shù)之間的相互引用以及相互獨(dú)立的關(guān)系驹暑,產(chǎn)生了extern和static關(guān)鍵字裳食。
下面矛市,詳細(xì)分析一下static關(guān)鍵字在編寫(xiě)程序時(shí)有的三大類(lèi)用法:

static全局變量

我們知道,一個(gè)進(jìn)程在內(nèi)存中的布局如圖1所示:
圖1

其中.text段保存進(jìn)程所執(zhí)行的程序二進(jìn)制文件诲祸,.data段保存進(jìn)程所有的已初始化的全局變量浊吏,.bss段保存進(jìn)程未初始化的全局變量(其他段中還有很多亂七八糟的段,暫且不表)烦绳。在進(jìn)程的整個(gè)生命周期中,.data段和.bss段內(nèi)的數(shù)據(jù)時(shí)跟整個(gè)進(jìn)程同生共死的配紫,也就是在進(jìn)程結(jié)束之后這些數(shù)據(jù)才會(huì)壽終就寢径密。

當(dāng)一個(gè)進(jìn)程的全局變量被聲明為static之后,它的中文名叫靜態(tài)全局變量躺孝。靜態(tài)全局變量和其他的全局變量的存儲(chǔ)地點(diǎn)并沒(méi)有區(qū)別享扔,都是在.data段(已初始化)或者.bss段(未初始化)內(nèi),但是它只在定義它的源文件內(nèi)有效植袍,其他源文件無(wú)法訪問(wèn)它惧眠。所以,普通全局變量穿上static外衣后于个,它就變成了新娘氛魁,已心有所屬,只能被定義它的源文件(新郎)中的變量或函數(shù)訪問(wèn)厅篓。

以下是一些示例程序:
file1.h如下:

#include 
void printStr();

我們?cè)趂ile1.c中定義一個(gè)靜態(tài)全局變量hello, 供file1.c中的函數(shù)printStr訪問(wèn).

#include "file1.h"
static char* hello ="hello cobing!";
void printStr()
{
    printf("%s\n", hello);
}

file2.c是我們的主程序所在文件秀存,file2.c中如果引用hello會(huì)編譯出錯(cuò).

#include "file1.h"
int main()
{
    printStr();
    printf("%s\n", hello);
    return0;
}

報(bào)錯(cuò)如下:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

file2.c: In function ‘main’:
file2.c:6: 錯(cuò)誤:‘hello’ 未聲明 (在此函數(shù)內(nèi)第一次使用)
file2.c:6: 錯(cuò)誤:(即使在一個(gè)函數(shù)內(nèi)多次出現(xiàn),每個(gè)未聲明的標(biāo)識(shí)符在其
file2.c:6: 錯(cuò)誤:所在的函數(shù)內(nèi)只報(bào)告一次羽氮。)
如果我們將file2.c改為下面的形式:

#include "file1.h"  
  
int main()  
{  
    printStr();  
    return 0;  
}  

則會(huì)順利編譯連接或链。

運(yùn)行程序后的結(jié)果如下:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

[liujx@server235 static]$ ./file2

hello cobing!

上面的例子中,file1.c中的hello就是一個(gè)靜態(tài)全局變量档押,它可以被同一文件中的printStr調(diào)用澳盐,但是不能被不同源文件中的file2.c調(diào)用。

static局部變量

普通的局部變量在椓钏蓿空間上分配叼耙,這個(gè)局部變量所在的函數(shù)被多次調(diào)用時(shí),每次調(diào)用這個(gè)局部變量在棧上的位置都不一定相同粒没。局部變量也可以在堆上動(dòng)態(tài)分配旬蟋,但是記得使用完這個(gè)堆空間后要釋放之。

static局部變量中文名叫靜態(tài)局部變量革娄。它與普通的局部變量比起來(lái)有如下幾個(gè)區(qū)別:

  1. 位置:靜態(tài)局部變量被編譯器放在全局存儲(chǔ)區(qū).data(注意:不在.bss段內(nèi)倾贰,原因見(jiàn)3))冕碟,所以它雖然是局部的,但是在程序的整個(gè)生命周期中存在匆浙。
  2. 訪問(wèn)權(quán)限:靜態(tài)局部變量只能被其作用域內(nèi)的變量或函數(shù)訪問(wèn)安寺。也就是說(shuō)雖然它會(huì)在程序的整個(gè)生命周期中存在,由于它是static的首尼,它不能被其他的函數(shù)和源文件訪問(wèn)挑庶。
  3. :靜態(tài)局部變量如果沒(méi)有被用戶初始化,則會(huì)被編譯器自動(dòng)賦值為0软能,以后每次調(diào)用靜態(tài)局部變量的時(shí)候都用上次調(diào)用后的值迎捺。這個(gè)比較好理解,每次函數(shù)調(diào)用靜態(tài)局部變量的時(shí)候都修改它然后離開(kāi)查排,下次讀的時(shí)候從全局存儲(chǔ)區(qū)讀出的靜態(tài)局部變量就是上次修改后的值凳枝。

以下是一些示例程序:
file1.h的內(nèi)容和上例中的相同,file1.c的內(nèi)容如下:

#include "file1.h"

void printStr()

{

    int normal = 0;

    static int stat = 0;//this is a static local var

    printf("normal = %d ---- stat = %d\n",normal, stat);

    normal++;

    stat++;

}

為了便于比較跋核,我定義了兩個(gè)變量:普通局部變量normal和靜態(tài)局部變量stat岖瑰,它們都被賦予初值0;

file2.c中調(diào)用file1.h:

#include "file1.h"

int main()

{

    printStr();

    printStr();

    printStr();

    printStr();

    printf("call stat in main: %d\n",stat);

    return0;

}

這個(gè)調(diào)用會(huì)報(bào)錯(cuò)砂代,因?yàn)閒ile2.c中引用了file1.c中的靜態(tài)局部變量stat蹋订,如下:


[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

file2.c: In function ‘main’:

file2.c:9: 錯(cuò)誤:‘stat’ 未聲明 (在此函數(shù)內(nèi)第一次使用)

file2.c:9: 錯(cuò)誤:(即使在一個(gè)函數(shù)內(nèi)多次出現(xiàn),每個(gè)未聲明的標(biāo)識(shí)符在其

file2.c:9: 錯(cuò)誤:所在的函數(shù)內(nèi)只報(bào)告一次刻伊。)

編譯器說(shuō)stat未聲明露戒,這是因?yàn)樗床坏絝ile1.c中的stat,下面注掉這一行:

#include "file1.h"

intmain()

{

    printStr();

    printStr();

    printStr();

    printStr();

    //  printf("call stat in main: %d\n",stat);

    return0;

}
[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

[liujx@server235 static]$ ./file2

normal = 0 ---- stat = 0

normal = 0 ---- stat = 1

normal = 0 ---- stat = 2

normal = 0 ---- stat = 3

運(yùn)行如上所示捶箱∶捣妫可以看出,函數(shù)每次被調(diào)用讼呢,普通局部變量都是重新分配撩鹿,而靜態(tài)局部變量保持上次調(diào)用的值不變。

需要注意的是由于static局部變量的這種特性悦屏,使得含靜態(tài)局部變量的函數(shù)變得不可重入节沦,即每次調(diào)用可能會(huì)產(chǎn)生不同的結(jié)果。這在多線程編程時(shí)可能會(huì)成為一種隱患础爬。需要多加注意甫贯。

static函數(shù)

相信大家還記得C++面向?qū)ο缶幊讨械膒rivate函數(shù),私有函數(shù)只有該類(lèi)的成員變量或成員函數(shù)可以訪問(wèn)看蚜。在C語(yǔ)言中叫搁,也有“private函數(shù)”,它就是接下來(lái)要說(shuō)的static函數(shù),完成面向?qū)ο缶幊讨衟rivate函數(shù)的功能渴逻。

當(dāng)你的程序中有很多個(gè)源文件的時(shí)候疾党,你肯定會(huì)讓某個(gè)源文件只提供一些外界需要的接口,其他的函數(shù)可能是為了實(shí)現(xiàn)這些接口而編寫(xiě)惨奕,這些其他的函數(shù)你可能并不希望被外界(非本源文件)所看到雪位,這時(shí)候就可以用static修飾這些“其他的函數(shù)”。
所以static函數(shù)的作用域是本源文件梨撞,把它想象為面向?qū)ο笾械膒rivate函數(shù)就可以了雹洗。
下面是一些示例:

file1.h如下:

#include 

static int called();

void printStr();

file1.c如下:

#include "file1.h"

static int called()

{

    return6;

}

void printStr()

{

    int  returnVal;

    returnVal = called();

    printf("returnVal=%d\n",returnVal);

}

file2.c中調(diào)用file1.h中聲明的兩個(gè)函數(shù),此處我們故意調(diào)用called():

#include "file1.h"

int main()

{

    int val;

    val = called();

    printStr();

    return0;

}

編譯時(shí)會(huì)報(bào)錯(cuò):

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

file1.h:3: 警告:‘called’ 使用過(guò)但從未定義

/tmp/ccyLuBZU.o: In function `main':

file2.c:(.text+0x12): undefined reference to `called'

collect2: ld 返回 1
因?yàn)橐昧薴ile1.h中的static函數(shù)卧波,所以file2.c中提示找不到這個(gè)函數(shù):undefined reference to 'called'

下面修改file2.c:

#include "file1.h"

int main()

{

    printStr();

    return0;

}

編譯運(yùn)行:

[liujx@server235 static]$ gcc -Wall file2.c file1.c -o file2

[liujx@server235 static]$ ./file2

returnVal=6

static函數(shù)可以很好地解決不同原文件中函數(shù)同名的問(wèn)題时肿,因?yàn)橐粋€(gè)源文件對(duì)于其他源文件中的static函數(shù)是不可見(jiàn)的。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末港粱,一起剝皮案震驚了整個(gè)濱河市螃成,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌啥容,老刑警劉巖锈颗,帶你破解...
    沈念sama閱讀 222,946評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件顷霹,死亡現(xiàn)場(chǎng)離奇詭異咪惠,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)淋淀,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,336評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)遥昧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人朵纷,你說(shuō)我怎么就攤上這事炭臭。” “怎么了袍辞?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,716評(píng)論 0 364
  • 文/不壞的土叔 我叫張陵鞋仍,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我搅吁,道長(zhǎng)威创,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,222評(píng)論 1 300
  • 正文 為了忘掉前任谎懦,我火速辦了婚禮肚豺,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘界拦。我一直安慰自己吸申,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,223評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著截碴,像睡著了一般梳侨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上隐岛,一...
    開(kāi)封第一講書(shū)人閱讀 52,807評(píng)論 1 314
  • 那天猫妙,我揣著相機(jī)與錄音,去河邊找鬼聚凹。 笑死割坠,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妒牙。 我是一名探鬼主播彼哼,決...
    沈念sama閱讀 41,235評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼湘今!你這毒婦竟也來(lái)了敢朱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 40,189評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤摩瞎,失蹤者是張志新(化名)和其女友劉穎拴签,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體旗们,經(jīng)...
    沈念sama閱讀 46,712評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蚓哩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,775評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了上渴。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岸梨。...
    茶點(diǎn)故事閱讀 40,926評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖曹阔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情赃份,我是刑警寧澤,帶...
    沈念sama閱讀 36,580評(píng)論 5 351
  • 正文 年R本政府宣布抓韩,位于F島的核電站,受9級(jí)特大地震影響恃慧,放射性物質(zhì)發(fā)生泄漏园蝠。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,259評(píng)論 3 336
  • 文/蒙蒙 一彪薛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧善延,春花似錦少态、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,750評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至侨歉,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間幽邓,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,867評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工牵舵, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留倦挂,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,368評(píng)論 3 379
  • 正文 我出身青樓方援,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親肯骇。 傳聞我的和親對(duì)象是個(gè)殘疾皇子祖很,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,930評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • C語(yǔ)言代碼是以文件為單位來(lái)組織的,在一個(gè)源程序的所有源文件中胚鸯,一個(gè)外部變量(注意不是局部變量)或者函數(shù)只能在一個(gè)源...
    交話費(fèi)的時(shí)間放寒假閱讀 706評(píng)論 0 1
  • 1笨鸡、c語(yǔ)言的函數(shù)有以下特點(diǎn): (1)才源程序由函數(shù)組成姜钳,一個(gè)主函數(shù)main()+若干其他函數(shù) C程序中的函數(shù)類(lèi)似文...
    滕王閣序閱讀 1,348評(píng)論 0 6
  • 普通全局變量穿上static的外衣后形耗,它就變成了新娘,已心有所屬激涤,只能被定義它的源文件(新郎)中的變量或函數(shù)使用了...
    憶億億光年閱讀 222評(píng)論 0 0
  • 姓名:劉小瓊 公司:寧波大發(fā)化纖有限公司 寧波盛和塾《六項(xiàng)精進(jìn)》第235期學(xué)員 【日精進(jìn)打卡第106天】 知~學(xué)習(xí)...
    劉小瓊123閱讀 61評(píng)論 0 0
  • 【請(qǐng)你勇敢】讓你難過(guò)的事情,有一天,你一定會(huì)笑著說(shuō)出來(lái)
    冰冰冰兒閱讀 173評(píng)論 0 0