2010-06-04 52 views
21

我想知道使用static關鍵字:範圍在文件限制爲變量,在C.理由使用靜態函數和變量用C

建立一個C程序,因爲我看到它是標準的方式到:

  • 有一堆c文件定義函數和變量,可能範圍限於static
  • 有一堆h文件,聲明相應c文件的函數和可能的變量,用於其他要使用的c文件。私有函數和變量不會在h文件中發佈。
  • 每個c文件分別編譯到o文件。
  • 所有o文件都鏈接到一個應用程序文件。

我看到兩個原因宣告gobal爲static,如果變量沒有在H文件公佈反正:

  • 一個是可讀性。通知未來的讀者,包括我自己,一個變量不能在任何其他文件中訪問。
  • 第二個是防止另一個c文件將變量重新聲明爲extern。我想鏈接器會不喜歡變量是externstatic。 (我不喜歡將文件重新聲明爲其他人擁有的變量爲extern,是否可以練習?)

任何其他原因?

同樣適用於static函數。如果原型文件未在h文件中發佈,其他文件可能無法使用該功能,那麼爲什麼要定義它static呢? 我可以看到相同的兩個原因,但沒有更多。

+0

六年後,我現在知道'靜態'不限制範圍,它給內部鏈接。如果您將翻譯單位視爲範圍,但不是正確的術語,則情況類似。 – Gauthier 2016-03-03 12:41:38

回答

23

當您談論通知其他讀者時,請將編譯器本身視爲讀者。如果一個變量聲明爲static,可能會影響到優化踢程度。

重新定義static變量extern是不可能的,但是編譯器會(像往常一樣),給你足夠的繩子吊死自己。

如果我在一個文件中寫入static int foo;而在另一個int foo;它們被認爲是不同的變量,儘管具有相同的名稱和類型 - 編譯器不會抱怨,但你可能會得到非常困惑後來嘗試讀取和/或者調試代碼。(如果我在第二種情況下寫extern int foo;,那將無法連接,除非我宣佈一個非靜態int foo;別的地方。)

全局變量很少出現在頭文件,但是當他們這樣做,他們應該聲明extern。如果不是,取決於你的編譯器,你可能會冒每個包含該頭文件的源文件聲明它自己的變量副本:最好這會導致鏈接失敗(多重定義的符號),最壞的情況是幾個令人迷惑的遮蔽情況。

+1

有趣的。我知道這個「頭文件中的extern global」仍然需要在c文件中定義,因爲h文件中的extern使其成爲單純的聲明。 – Gauthier 2010-06-04 12:46:38

+1

你是對的。 – crazyscot 2010-06-04 15:20:57

7

通過在文件級聲明變量static(函數中的static具有不同的含義),您禁止其他單元訪問它,例如,如果您嘗試在另一個單元內使用變量(使用extern聲明),鏈接器將不會找到此符號。

+0

這正是我提到的兩個原因之一:「第二個是防止另一個c文件使用看似範圍受限的全局,將其重新聲明爲extern。我想知道這種做法的質量? – Gauthier 2010-06-04 12:10:54

+0

@Gaunthier所以你的文章有內部衝突,然後 – qrdl 2010-06-04 12:16:50

+2

國際海事組織,'靜態'在所有三個衆所周知的用途(文件變量,函數變量,函數)具有相同的含義,即:「這有限的範圍,並有一個常量在整個計劃執行過程中的地址「 – Gauthier 2010-06-04 12:17:37

1

如果一個全局變量被聲明爲靜態的,編譯器有時可以做出比沒有的更好的優化。因爲編譯器知道變量不能從其他源文件訪問,所以它可以更好地推斷你的代碼正在做什麼(比如「這個函數不修改這個變量」),這有時會導致它生成更快的代碼。很少的編譯器/鏈接器可以跨不同的翻譯單元進行這種優化。

6

當您聲明一個靜態函數時,對該函數的調用是「接近調用」,理論上它比「遠程調用」執行得更好。你可以谷歌的更多信息。 This是我用簡單的谷歌搜索找到的。

+0

也有趣,雖然平臺依賴(我的目標只有一個CALL指令絕對,並沒有遠/近)。 – Gauthier 2010-06-04 13:14:54

+0

例如gcc可以在許多平臺上爲靜態函數切換調用約定(更快)。 – nos 2010-06-04 17:00:01

-1

我最喜歡的靜態使用方法是能夠存儲我不需要的方法注入或創建一個對象來使用,我看到它的方式是,私有靜態方法總是有用的,其中公共靜態你必須把一些有更多的時間思考你在做什麼來避免crazyscot定義爲什麼,讓你自己過多的繩索,並不小心把自己掛起來!

我喜歡爲我的大多數項目保留一個Helper類的文件夾,這些項目主要由靜態方法組成,可以快速高效地執行任務,無需任何對象!

+2

問題是關於C,而不是C++。在C中沒有類,沒有方法,也沒有私人成員。而且,在C++中,靜態函數和靜態方法有所不同。 – 2010-06-04 14:15:00

+1

糟糕! 我意識到我絕對誤讀了這個問題。 – 2010-06-06 06:00:32

0

如果您在文件ac中聲明變量foo而不將其設爲靜態,並且文件bc中的變量foo不會變爲靜態,則兩者都會自動extern,這意味着如果初始化這兩個文件並且分配相同的內存如果它沒有抱怨的位置。期待有趣的調試你的代碼。

如果你寫在文件公元前文件AC函數foo()不使其靜態的,一個函數foo()不使其靜態,接頭可以抱怨,但如果沒有,爲foo的所有呼叫()將調用相同的函數。期待有趣的調試你的代碼。