學習筆記 關鍵字static 和 extern

2021-07-05 01:11:38 字數 4982 閱讀 8911

static  主要修飾變數和修飾函式

靜態變數:儲存在靜態區(全域性區)

靜態區域性變數:

靜態區域性變數屬於靜態儲存方式,它具有以下特點:

(1) 靜態區域性變數在函式內定義 ,它的生存期為整個源程式,但是其作用域仍與自動變數相同,只能在定義該變數的函式內使用該變數。退出該函式後, 儘管該變數還繼續存在,但不能使用它。

(2)允許對構造類靜態區域性量賦初值  例如陣列,若未賦以初值,則由系統自動賦以0值。

(3)對基本型別的靜態區域性變數若在說明時未賦以初值,則系統自動賦予0值。而對自動變數不賦初值,則其值是不定的。 根據靜態區域性變數的特點,可以看出它是一種生存期為整個源程式的變數。雖然離開定義它的函式後不能使用,但如再次呼叫定義它的函式時,它又可繼續使用, 而且儲存了前次被呼叫後留下的值。 因此,當多次呼叫乙個函式且要求在呼叫之間保留某些變數的值時,可考慮採用靜態區域性變數。雖然用全域性變數也可以達到上述目的,但全域性變數有時會造成 意外的***,因此仍以採用區域性靜態變數為宜。

靜態全域性變數:(其他檔案extern 也不能使用這個變數)

全域性變數(外部變數)的說明之前再冠以static 就構成了靜態的全域性變數。全域性變數本身就是靜態儲存方式,靜態全域性變數當然也是靜態儲存方式,這兩者在儲存方式上並無不同。

這兩者的區別在於非靜態全域性變數的

作用域是整個源程式, 當乙個源程式由多個原始檔組成時,非靜態的全域性變數在各個原始檔中都是有效的。

而靜態全域性變數則限制了其作用域, 即只在 定義該變數的原始檔內有效,在同一源程式的其它原始檔中不能使用它。

由於靜態全域性變數的

作用域是從定義之處開始,到檔案結尾處結束,在定義之處前面的那些**行也不能使用它。想要使用就得在前面再加 extern 或定義在檔案頂端侷限於乙個原始檔內,只能為該原始檔內的函式公用, 因此可以避免在其它原始檔中引起錯誤。

從以上分析可以看出, 把區域性變數改為靜態變數後是改變了它的儲存方式(即改變了它的生存週期),

把全域性變數改變為靜態變數 後是改變了它的作用域, 限制了它的使用範圍。因此static 這個說明符在不同的地方所起的作用是不同的。

static 修飾函式:

當乙個源程式由多個原始檔組成時,c語言根據函式能否被其它原始檔中的函式呼叫,將函式分為內部函式和外部函式。

內部函式(又稱靜態函式)

如果在乙個原始檔中定義的函式,只能被本檔案中的函式呼叫,而不能被同一程式其它檔案中的函式呼叫,這種函式稱為內部函式。

定義乙個內部函式,只需在函式型別前再加乙個「static」關鍵字即可,關鍵字「static」,譯成中文就是「靜態的」,所以內部函式又稱靜態函式。但此處「static」的含義不是指儲存方式,而是指對函式的作用域僅侷限於本檔案。

靜態函式的好處:

多檔案允許函式重名:不同的人編寫不同的函式時,不用擔心自己定義的函式,是否會與其它檔案中的函式同名 。

其他檔案裡不能呼叫該函式。

靜態函式儲存於靜態儲存區。

靜態函式被呼叫時不會發生出入棧操作。

c++裡對 static賦予了第三個作用,修飾類的成員變數和成員函式成為靜態成員變數和靜態成員函式。

對於靜態成員變數,無論這個類的物件被定義了多少個,靜態資料成員在程式中也只有乙份拷貝,由該型別的所有物件共享訪問。也就是說,靜態資料成員是該類的所有物件所共有的。對該類的多個物件來說,靜態資料成員只分配一次記憶體,供所有物件共用。

靜態成員函式與靜態資料成員一樣,都是類的內部實現,屬於類定義的一部分。普通的成員函式一般都隱含了乙個this指標,this指標指向類的物件本身,因為普通成員函式總是具體的屬於某個類的具體物件的。通常情況下,this是預設的。如函式fn()實際上是this->fn()。但是與普通函式相比,靜態成員函式由於不是與任何的物件相聯絡,因此它不具有this指標。從這個意義上講,靜態成員函式無法訪問屬於類物件的非靜態資料成員,也無法訪問非靜態成員函式,靜態成員函式只能呼叫其餘的靜態成員函式。

extern:

extern(外部引用)可以置於變數或者函式前,以標示變數或函式的定義在別的檔案中,在乙個檔案中用到的extern這些變數或函式是外來的,不是本檔案定義的,提示編譯器遇到此變數和函式時在其他模組中尋找其定義。

注意:只有其他檔案中的全域性變數才能被其他檔案所extern。

例如:  extern int val ;

注:此處的函式型別可以省略,即 extern val ;

因為extern的作用就是告訴編譯器這個變數是在其他檔案中定義的(是外援),所以在編譯的時候要是看到val變數時會認為它是存在,不會報錯。只有在鏈結的時候鏈結器才會去其它obj檔案中尋找val變數的定義(位址),找到則順利鏈結,否則報錯。因為編譯器只需要知道extern所宣告變數的名字就可以了,所以extern int val 可以寫成 extern val(即省略變數型別)。

static 與 extern 聯絡:

加了static修飾的全域性變數或函式,無法在使用extern在其他原始檔中使用。

深層揭密extern "c"

在c++程式中呼叫被c編譯器編譯後的函式,為什麼要加extern "c" ?

答案:c++語言支援函式過載,c語言不支援函式過載。函式被c++編譯後在庫中的名字與c語言的不同。假設某個函式的原型為void foo(int x, int y)。該函式被c編譯器編譯後在庫中的名字為_foo,而c++編譯器則會產生像_foo_int_int之類的名字

c++提供了c連線交換指定符號extern "c"解決名字匹配問題。

被extern "c"修飾的變數和函式是按照c語言方式編譯和連線的;

首先看看c++中對類似c的函式是怎樣編譯的:

作為一種物件導向的語言,c++支援函式過載,而過程式語言c則不支援。

函式被c++編譯後在符號庫中的名字與c語言的不同。

例如:假設某個函式的原型為 

void foo( int x, int y );

該函式被c編譯器編譯後在符號庫中的名字為_foo,而c++編譯器則會產生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,但是都採用了相同的機制,生成的新名字稱為「mangled name」)。

_foo_int_int這樣的名字包含了函式名、函式引數數量及型別資訊,c++就是靠這種機制來實現函式過載的。

例如,在c++中,函式void foo( int x, int y )與void foo( int x, float y )編譯生成的符號是不相同的,後者為_foo_int_float。

同樣地,c++中的變數除支援區域性變數外,還支援類成員變數和全域性變數。使用者所編寫程式的類成員變數可能與全域性變數同名,我們以"."來區分。而本質上,編譯器在進行編譯時,與函式的處理相似,也為類中的變數取了乙個獨一無二的名字,這個名字與使用者程式中同名的全域性變數名字不同。

在c++中引用c語言中的函式和變數,在包含c語言標頭檔案(假設為cexample.h)時,需進行下列處理:

extern "c"

在c語言的標頭檔案中,對其外部函式只能指定為extern型別,c語言中不支援extern "c"宣告,在.c檔案中包含了extern "c"時會出現編譯語法錯誤。

在c中引用c++語言中的函式和變數時,c++的標頭檔案需新增extern "c",但是在c語言中不能直接引用宣告了extern "c"的該標頭檔案,應該僅在c檔案中將c++中定義的extern "c"函式宣告為extern型別。

static關鍵字筆記

static關鍵字 作用 是乙個修飾符,用於修飾成員 成員變數,成員方法 1.被static 修飾後的成員變數只有乙份 2.當成員被static修飾之後,多了一種訪問方式,除了可以物件呼叫之外,還可以被類直接呼叫 類名.靜態成員 static的特點 1.隨著類的載入而被載入 2.優先於物件的存在 3...

關鍵字static學習

關於static關鍵字的使用,它可以用來修飾的成員變數和成員方法,被修飾的成員是屬於類的,而不是單單是屬 於某個物件的。也就是說,既然屬於類,就可以不靠建立物件來呼叫了。當 static 修飾成員變數時,該變數稱為類變數。該類的每個物件都共享同乙個類變數的值。任何物件都可以更改 該類變數的值,但也可...

Java學習筆記 static關鍵字

1 可以修飾成員變數和成員方法 2 隨著類的載入而載入 3 優先於物件存在 4 被類的所有物件共享 這是我們判斷該不該使用靜態的依據 5 通過類名呼叫 既可以通過物件名呼叫,也可以通過類名呼叫,建議通過類名呼叫 靜態的內容在方法區的靜態區 1 在靜態中沒有this物件 2 靜態只能訪問靜態 1 所屬...