天天看點

關鍵字static的使用詳解

一、可執行程式記憶體配置設定

一個程式的3個基本段:text段,data段,bss段

關鍵字static的使用詳解

BSS BSS(Block Started by Symbol)通常是指用來存放程式中未初始化的全局變量和靜态變量的一塊記憶體區域。

特點是:可讀寫的,在程式執行之前BSS段會自動清0。

是以,未初始的全局變量在程式執行之前已經成0了。

注意和資料段的差別,BSS存放的是未初始化的全局變量和靜态變量,資料段存放的是初始化後的全局變量和靜态變量。

UNIX下可使用size指令檢視可執行檔案的段大小資訊。如size a.out。

資料段.data 存放在編譯階段(而非運作時)就能确定的資料,可讀可寫。

也就是通常所說的靜态存儲區,賦了初值的全局變量和賦初值的靜态變量存放在這個區域,常量也存在這個區域。資料段,代碼段在程式運作之前就已經确定了的。

代碼段.text 代碼段通常是指用來存放程式執行代碼的一塊記憶體區域。

這部分區域的大小在程式運作前就已經确定,并且記憶體區域通常屬于隻讀, 某些架構也允許代碼段為可寫,即允許自修改程式。

在代碼段中,也有可能包含一些隻讀的常數變量,例如字元串常量等。

text段在編譯時确定,記憶體中被映射為隻讀,但date段與bss段是可寫的。

棧區(堆棧區stack)

堆棧是由編譯器自動配置設定釋放,存放函數的參數和局部變量的值(auto類型),操作方式類似于資料結構中的棧。棧的申請是由系統自動配置設定,如在函數内部申請一個局部變量int h,同時判斷所申請空間是否小于棧的剩餘空間,如果小于則為其開辟空間,為程式提供記憶體,否則将報異常提示棧溢出。

堆(heap)

堆一般由程式員配置設定釋放,若程式員不釋放,程式結束可能由OS回收。

它與資料結構中的堆是兩回事,配置設定方式類似于連結清單,申請則是程式員自己操作使用malloc或new。

申請過程比較複雜,當系統收到程式的申請時,會周遊記錄空閑記憶體位址的連結清單,以求尋找第一個空間大于所申請空間的堆節點,然後将該節點從空閑節點連結清單中删除,并将該節點的空間配置設定給程式,有些情況下,新申請的記憶體塊的首位址記錄本次配置設定的記憶體塊的大小,這樣在free()時能正确的釋放記憶體空間。

全局靜态存儲區

全局變量與靜态變量的存儲是放在一塊的,初始化的全局變量與靜态變量存放在一塊區域,未初始化的全局變量與未初始化的靜态變量存放在相鄰的另一塊區域。

文字常量區

常量字元串就是放在該部分,隻讀存儲區,程式結束後由系統釋放

程式代碼區

存放程式的二進制代碼區。

兩者之間差別是:代碼段,資料段,堆棧段是cpu級别的概念,五大分區屬于語言級别的概念,兩者是不同的概念。

關鍵字static的使用詳解

左邊是UNIX系統的執行檔案,右邊是程序對應的邏輯位址空間的劃分情況

二、static 變量

static變量主要區分靜态全局變量和全局變量、局部變量和靜态局部變量之間的差別。

靜态全局變量、全局變量的差別主要通過生存周期和作用域來差別。

全局變量

靜态全局變量

生存周期

程式運作到程式結束

程式運作開始到程式結束

作用域

所有的代碼

隻有目前檔案可以通路

代碼段中位置

全局資料區

a.靜态全局變量和全局變量均存放在資料段.data中;

b. 靜态局部變量在函數内定義,生存期為整個源程式,但作用域與自動變量相同,隻能在定義該變量的函數内使用。退出該函數後, 盡管該變量還繼續存在,但不能使用它。

c. 對基本類型的靜态局部變量若在說明時未賦以初值,則系統自動賦予0值。而對自動變量不賦初值,則其值是不定的。

d.全局變量本身就是靜态存儲方式, 靜态全局變量當然也是靜态存儲方式。但是他們的作用域,非靜态全局 變量的作用域是整個源程式(多個源檔案可以共同使用);而靜态全局變量則限制了其作用域, 即隻在定義該變量的源檔案内有效, 在同一源程式的其它源檔案中不能使用它。

以下是b.c 和 a.c源代碼

關鍵字static的使用詳解

編譯

執行結果:

關鍵字static的使用詳解

執行結果

由編譯結果可知,檔案a.c可以通路到b.c檔案中的靜态全局變量b。

關鍵字static的使用詳解

編譯結果

關鍵字static的使用詳解

由編譯結果可知,檔案a.c無法通路到b.c檔案中的靜态全局變量b,是以編譯報錯。

靜态局部變量、局部變量的差別主要通過生存周期和作用域來差別。

局部變量

靜态局部變量

函數調用到函數傳回

函數内部

靜态局部變量存放在資料段.data中,局部變量在棧中;靜态局部變量和局部變量都隻能在函數體内部才可以通路。

函數每次通路的靜态局部變量,該變量的值為最後一次通路修改後的值。

舉例:

關鍵字static的使用詳解

對于普通的局部變量,每次調用的時候,都會在棧裡初始化1次,

關鍵字static的使用詳解

函數中靜态變量aa 隻初始化一次,每次通路的值應該是上一次調用到該函數時最後處理的結果,

三、static 函數

在函數的傳回類型前加上關鍵字static,函數就被定義成為靜态函數。

函數的定義和聲明預設情況下是extern的,但靜态函數隻是在聲明他的檔案當中可見,不能被其他檔案所用。

static函數(也叫内部函數)隻能被本檔案中的函數調用,而不能被同一程式其它檔案中的函數調用。

差別于一般的非靜态函數(外部函數) static在c裡面可以用來修飾變量,也可以用來修飾函數。

先看用來修飾變量的時候。變量在c裡面可分為存在全局資料區、棧和堆裡。

其實我們平時所說的堆棧是棧而不包含堆,不要弄混。

<1>其他檔案中可以定義相同名字的函數,不會發生沖突,不用擔心自己定義的函數,是否會與其它檔案中的函數同名,因為同名也沒有關系。

<2> 靜态函數不能被其他檔案所用。存儲說明符auto,register,extern,static,對應兩種存儲期:自動存儲期和靜态存儲期。

<3> 統計次數功能 聲明函數的一個局部變量,并設為static類型,作為一個計數器,這樣函數每次被調用的時候就可以進行計數。這是統計函數被調用次數的最好的辦法,因為這個變量是和函數息息相關的,而函數可能在多個不同的地方被調用,是以從調用者的角度來統計比較困難。

<4> 靜态函數會被自動配置設定在一個一直使用的存儲區,直到退出應用程式執行個體,避免了調用函數時壓棧出棧,速度快很多。

a.c

b.c

關鍵字static的使用詳解

由編譯結果可知,a檔案通路不到b檔案中的靜态函數func。

來自公衆号:一口Linux

連結:https://blog.csdn.net/daocaokafei/article/details/112910810