2012-11-20 50 views
1

我正在寫一個僅包含頭文件的庫,在向我提供給用戶staticinline的函數聲明之間我無法下定決心。在這種情況下,我有什麼理由選擇另一個呢?我應該使用靜態還是內聯?

+0

兩者都會達到目的。當函數內部聲明瞭一個'static'變量時,就會出現差異。 'inline'函數將只爲所有文件創建該變量的一個副本,但是'static'函數將爲每個文件創建一個副本。 – iammilind

+0

你是否正在編寫應該能夠很好地工作的代碼,如** C和C++ **?語言的規則不同。 –

+0

@ Cheersandhth.-Alf C++,但我對兩種情況都感興趣。 – qdii

回答

6

他們都提供不同的功能。

有使用inline關鍵字的兩個含義(§7.1.3/4):

  1. 暗示編譯器,在呼叫的點功能體的取代是在通常的功能,優選調用機制。
  2. 即使省略了內聯替換,也會遵循內聯的其他規則(特別是w.r.t One Definition Rule)。

在功能上的static關鍵字強制inline函數有一個內部連接(內聯函數具有外部連接)這樣的功能中的每一個實例被視爲一個單獨的功能(各功能的地址是不同)以及這些功能的每個實例有靜態局部變量的字符串字面量自己的副本&(內聯函數只有一個,這些

+0

它在C++ 11上是否正確? – qdii

+0

@qdii:是的,它的確如此。 –

+2

+1 @qdii:強調不僅每個'static'函數都有它自己的靜態變量,文字等等,而且代碼將被複制(如果它沒有被內聯)並且會膨脹你的二進制和影響性能(不太適合指令緩存) –

3

staticinline是正交的。換句話說,你可以有一個或兩個或沒有。每個都有自己的獨立用途,決定是否使用它們。

+0

我覺得'無'選項是不可能的頭只庫。另外,OP正在詢問何時使用。這個答案是不完整的。不幸的是,我的+1現在被鎖定;你可以考慮它的個人資料,而不是答案。 :| – iammilind

+0

@iammilind問題是關於兩者之間的選擇。我的回答是試圖解釋你不必在它們之間做出選擇。您既可以使用它們,也可以不使用它們。另外,OP沒有指定他只是在討論頭文件。 –

+0

效果是正交的,這是真的。仍然在實際使用中存在連接,所以一個並不完全不常見的編輯操作是爲一組函數改變'static'→'inline',反之亦然。即在名稱空間作用域和類作用域之間移動函數時。 –

1

如果該功能不共享類狀態:static。爲了使功能static可以受益於在任何地方被稱爲。

如果功能比較小而明確:inline

+0

+1用於解決成員函數。請注意,'static'對於非成員函數具有不同的含義。 –

+0

'如果函數相對較小且清晰:inline',那麼用現代編譯器來決定自己的宏內嵌風格並不是問題。 – iammilind

1

複印件(這個答案是基於C99規則;你的問題被標記無線TH C和C++和C++中的規則很可能是不同的)

如果聲明的功能只是inline,那麼你的函數的定義是內嵌定義。編譯器不需要對翻譯單元中的函數的所有調用使用內聯定義 - 可以假定在另一個翻譯單元中提供了相同功能的外部定義,並將其用於部分或全部調用。在只有標題的庫中,不是就是這樣一個外部定義,所以使用它的程序可能在鏈接時失敗並且缺少定義。

在另一方面,你可以聲明函數既inlinestatic。在這種情況下,編譯器必須使用您爲翻譯單元中的函數的所有調用提供的定義,無論它是否實際內聯它們。這適用於僅包含標題的庫(儘管編譯器對於聲明爲inline static的函數的行爲可能與僅聲明static的函數完全相同,在這兩種情況下都會將其認爲是有益的,因此實際上可能存在很少有隻能通過static獲得)。

+0

C++中的規則確實不同。在C++中,一個'inline'函數默認具有外部鏈接,並且從函數中使用內部鏈接事物沒有限制。在C++中,純首標代碼的首選用法就是「內聯」,並帶有隱含的外部鏈接。 –

+0

@ Cheersandhth.-Alf:在C語言中,'inline'函數默認具有外部*鏈接*,但它們不一定提供外部*定義*。聽起來,如果OP希望他們的僅頭文件的庫在C和C++中都可用,那麼他們應該使用條件編譯來僅在C中使用'static'。 – caf

3

注意:此答案適用於C++。對於C,請參閱caf's answer。兩種語言不同。

static有兩個相關的含義:

  • 對於在命名空間內的功能,static給出了函數內部聯動,這實際上意味着該名稱不鏈接可見。 static也可以以這種方式用於數據,但對於數據,此用法在C++ 03(C++ 03附錄D中的§D.2,規範性標準)中不推薦使用。儘管如此,常量默認具有內部鏈接(因爲數據的使用已過時,所以不要將其明確表達出來)。

  • 對於一類的功能,static去除隱this參數,所以該函數可以而不類的對象被調用。

在頭部中的一個通常會不使用函數內部聯動,因爲人們不希望的功能在其中被包括在報頭的每個編譯單元被複制。

常見的做法是改爲使用一個名爲detail嵌套命名空間,當需要不屬於公共模塊接口的一部分類或函數,並希望減少污染普通的命名空間(即,降低潛在用於名稱衝突)。這個約定由Boost庫使用。與包含guard符號一樣,這個約定表示在當前C++中缺少模塊支持,其中一個基本上被簡化爲通過約定來模擬一些關鍵的語言特性。

inline也有兩個相關的含義:

  • 對於在名字空間域中的函數它告訴該函數的定義被有意地在每一個編譯單元,其中用它’ s提供編譯器。實際上,這會使鏈接器忽略該函數的多個定義,並且可以在頭文件中定義非模板函數。雖然模板可用於模擬數據的效果inline,但數據沒有相應的語言功能。

  • 它也不幸,使編譯器強大的暗示調用該函數最好在機器代碼擴展「在線」。

第一個含義是inline的唯一保證含義。

通常,將inline應用於頭文件中的每個函數定義。有一個例外,即直接在類定義中定義的函數。這樣的函數自動聲明爲inline(即,您避免鏈接器抗議而沒有明確添加單詞inline,因此在此上下文中的一個實際用法是將inline應用於類中的函數聲明,以告知讀者該定義函數稍後在頭文件中)。

因此,雖然看起來你對staticinline –的含義有點困惑,但它們不可互換! –你’重要的是,staticinline以某種方式連接。移動(免費)函數列一類的以命名空間範圍,你會改變staticinline和移動從命名空間範圍功能分爲一類,你會改變inlinestatic。雖然它不是一個常見的事情,但我發現在重構只有標頭的代碼時這並不罕見。

總結:

  • 使用inline在一個頭文件中定義的每個命名空間範圍功能。特別是,使用inline作爲函數模板的專門化,因爲函數模板只能是完全專用的,完全專業化是普通函數。如果未能將inline應用於頭文件中的函數模板專用化,通常會導致鏈接錯誤。

  • 使用一些特殊的嵌套命名空間,例如稱爲detail以避免對內部實現細節名稱造成污染。

  • 對於靜態類成員使用static

  • 不要使用static來明確說明一個常量具有內部鏈接,因爲在C++ 03中不推薦使用static(儘管表面上C++ 11已經刪除了棄用)。

  • 請記住,雖然inline可以將’應用於數據,但通過使用模板可以實現幾乎相同(實踐中)的效果。但是,如果您確實需要一些大的共享常量數據,並在頭文件中實現,我建議通過inline函數生成對數據的引用。它更容易編碼,並且更容易理解讀者的代碼。 :-)

相關問題