我正在寫一個僅包含頭文件的庫,在向我提供給用戶static
或inline
的函數聲明之間我無法下定決心。在這種情況下,我有什麼理由選擇另一個呢?我應該使用靜態還是內聯?
回答
他們都提供不同的功能。
有使用inline
關鍵字的兩個含義(§7.1.3/4):
- 它暗示編譯器,在呼叫的點功能體的取代是在通常的功能,優選調用機制。
- 即使省略了內聯替換,也會遵循內聯的其他規則(特別是w.r.t One Definition Rule)。
在功能上的static
關鍵字強制inline
函數有一個內部連接(內聯函數具有外部連接)這樣的功能中的每一個實例被視爲一個單獨的功能(各功能的地址是不同)以及這些功能的每個實例有靜態局部變量的字符串字面量自己的副本&(內聯函數只有一個,這些)
它在C++ 11上是否正確? – qdii
@qdii:是的,它的確如此。 –
+1 @qdii:強調不僅每個'static'函數都有它自己的靜態變量,文字等等,而且代碼將被複制(如果它沒有被內聯)並且會膨脹你的二進制和影響性能(不太適合指令緩存) –
static
和inline
是正交的。換句話說,你可以有一個或兩個或沒有。每個都有自己的獨立用途,決定是否使用它們。
我覺得'無'選項是不可能的頭只庫。另外,OP正在詢問何時使用。這個答案是不完整的。不幸的是,我的+1現在被鎖定;你可以考慮它的個人資料,而不是答案。 :| – iammilind
@iammilind問題是關於兩者之間的選擇。我的回答是試圖解釋你不必在它們之間做出選擇。您既可以使用它們,也可以不使用它們。另外,OP沒有指定他只是在討論頭文件。 –
效果是正交的,這是真的。仍然在實際使用中存在連接,所以一個並不完全不常見的編輯操作是爲一組函數改變'static'→'inline',反之亦然。即在名稱空間作用域和類作用域之間移動函數時。 –
如果該功能不共享類狀態:static
。爲了使功能static
可以受益於在任何地方被稱爲。
如果功能比較小而明確:inline
+1用於解決成員函數。請注意,'static'對於非成員函數具有不同的含義。 –
'如果函數相對較小且清晰:inline',那麼用現代編譯器來決定自己的宏內嵌風格並不是問題。 – iammilind
複印件(這個答案是基於C99規則;你的問題被標記無線TH C和C++和C++中的規則很可能是不同的)
如果聲明的功能只是inline
,那麼你的函數的定義是內嵌定義。編譯器不需要對翻譯單元中的函數的所有調用使用內聯定義 - 可以假定在另一個翻譯單元中提供了相同功能的外部定義,並將其用於部分或全部調用。在只有標題的庫中,不是就是這樣一個外部定義,所以使用它的程序可能在鏈接時失敗並且缺少定義。
在另一方面,你可以聲明函數既inline
和static
。在這種情況下,編譯器必須使用您爲翻譯單元中的函數的所有調用提供的定義,無論它是否實際內聯它們。這適用於僅包含標題的庫(儘管編譯器對於聲明爲inline static
的函數的行爲可能與僅聲明static
的函數完全相同,在這兩種情況下都會將其認爲是有益的,因此實際上可能存在很少有隻能通過static
獲得)。
C++中的規則確實不同。在C++中,一個'inline'函數默認具有外部鏈接,並且從函數中使用內部鏈接事物沒有限制。在C++中,純首標代碼的首選用法就是「內聯」,並帶有隱含的外部鏈接。 –
@ Cheersandhth.-Alf:在C語言中,'inline'函數默認具有外部*鏈接*,但它們不一定提供外部*定義*。聽起來,如果OP希望他們的僅頭文件的庫在C和C++中都可用,那麼他們應該使用條件編譯來僅在C中使用'static'。 – caf
注意:此答案適用於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
應用於類中的函數聲明,以告知讀者該定義函數稍後在頭文件中)。
因此,雖然看起來你對static
和inline
–的含義有點困惑,但它們不可互換! –你’重要的是,static
和inline
以某種方式連接。移動(免費)函數列一類的以命名空間範圍,你會改變static
→ inline
和移動從命名空間範圍功能分爲一類,你會改變inline
→ static
。雖然它不是一個常見的事情,但我發現在重構只有標頭的代碼時這並不罕見。
總結:
使用
inline
在一個頭文件中定義的每個命名空間範圍功能。特別是,使用inline
作爲函數模板的專門化,因爲函數模板只能是完全專用的,完全專業化是普通函數。如果未能將inline
應用於頭文件中的函數模板專用化,通常會導致鏈接錯誤。使用一些特殊的嵌套命名空間,例如稱爲
detail
以避免對內部實現細節名稱造成污染。對於靜態類成員使用
static
。不要使用
static
來明確說明一個常量具有內部鏈接,因爲在C++ 03中不推薦使用static
(儘管表面上C++ 11已經刪除了棄用)。請記住,雖然
inline
可以將’應用於數據,但通過使用模板可以實現幾乎相同(實踐中)的效果。但是,如果您確實需要一些大的共享常量數據,並在頭文件中實現,我建議通過inline
函數生成對數據的引用。它更容易編碼,並且更容易理解讀者的代碼。 :-)
- 1. 我應該使用SingleTone還是靜態?
- 2. 我應該使用靜態方法還是靜態字段
- 3. 我應該使用新的自我還是新的靜態?
- 4. 我應該爲我的應用使用動態還是靜態數據?
- 5. 我應該去靜態方法還是非靜態方法?
- 6. 我應該使用UITableView節頭還是靜態UITableViewCell?
- 7. 我應該在這個問題中使用內聯還是#define?
- 8. 我們應該考慮使用靜態鏈接還是動態鏈接?
- 9. 我應該創建靜態方法還是抽象超類
- 10. 我應該使用全局變量的靜態類還是隻使用靜態屬性?
- 11. 模型的泛型超類應該是靜態還是單態?
- 12. Netty 4頭文件:我應該使用靜態方法還是實例方法?
- 13. 我應該使用靜態字段還是SharedPreferences來存儲自定義對象?
- 14. 片段內部類應該是靜態
- 15. 類方法可以是內聯方式還是靜態方式?
- 16. 在這種情況下,我應該使用簡單還是多態關聯? [Rails]
- 17. 應該在Android中的適配器是靜態內部類還是非靜態內部類
- 18. 我應該加入還是應該聯盟
- 19. 我應該使用public $ var還是應該使用__construct()?
- 20. 我應該聲明我的對象是全局的還是靜態的?
- 21. 我應該如何結合使用CakePHP的靜態+非靜態內容
- 22. 我應該使用PurePDF還是AlivePdf
- 23. 我應該使用ABPersonViewController還是ABUnknownPersonViewController
- 24. 我應該使用Series.replace還是Series.str.replace?
- 25. 我應該使用requestanimationframe還是setTimeout?
- 26. 我應該使用SASS還是SCSS?
- 27. 我應該使用Boost.GIL還是死了?
- 28. 我應該使用Flash還是Java?
- 29. 我應該使用partial還是show.html.erb?
- 30. 我應該使用TNSNAMES.ORA還是tnsnames.ora?
兩者都會達到目的。當函數內部聲明瞭一個'static'變量時,就會出現差異。 'inline'函數將只爲所有文件創建該變量的一個副本,但是'static'函數將爲每個文件創建一個副本。 – iammilind
你是否正在編寫應該能夠很好地工作的代碼,如** C和C++ **?語言的規則不同。 –
@ Cheersandhth.-Alf C++,但我對兩種情況都感興趣。 – qdii