C99 inline
語義很微妙 - 事實上,語言的整個部分(存儲持續時間與鏈接,暫定和內聯定義)是一團糟。
儘管inline
在包含存儲類說明符(static
或extern
)的定義中充當編譯器提示,並且基本上可以忽略,但如果不存在說明符,則語義會更改。
像inline int fun(void) { ... }
的定義做兩兩件事:
首先,它聲明與外部鏈接的標識符,但不提供相應的外部定義。這意味着這種定義必須由不同的翻譯單位提供,否則我們最終會出現未定義的行爲(可能表現爲未能鏈接)。
其次,它提供了一個內聯定義,它是外部替代的替代。由於函數體在當前的翻譯單元中可見,因此編譯器可以使用它來內聯函數或類型專門化。
爲了獲得外部定義,直到fairly recently,我認爲有必要在另一個翻譯單元(或假的,與4行預處理器代碼)重複函數定義。
然而,這不是必要的:一個單一的代碼線 - 其包括extern
說明符的功能的重新聲明 - 是足以使直列式定義到外部的一個。
在你的榜樣,這將意味着將
inline int foo(void)
{
return 42;
}
成一個頭文件foo.h
並提供與內容
#include "foo.h"
// force definition to be external instead of inline
// I believe inline could be omitted, but it doesn't hurt
extern inline foo(void);
爲什麼這是有用的源文件foo.c
?由於C缺乏模板,所以通用代碼通常會帶來性能損失,因爲您需要使用void*
和函數指針(或更復雜的情況下,vtables)來僞造泛型。但是,只有當相關函數定義在當前翻譯單元中可見時,足夠智能的優化程序才能獲得模板的大多數(可能全部)性能優勢,但是(在沒有鏈接時優化的情況下)。
儘管可以通過在頭文件中添加static
定義來實現此目的,但這可能會使代碼大小增加到與C++模板相同的不可接受的級別。
相比之下,使用C99 inline
函數,編譯器可以自由地忽略內聯定義而偏向外部定義,甚至可以駐留在共享庫中。
功能的一個很好的例子是qsort()
,stdlib.h
的內聯定義和libc.so
的外聯定義。 qsort()
沒有先驗原因比std::sort()
慢。
什麼是編譯器? –
在gcc 4.7版上工作得很好。 – unxnut
什麼是錯誤信息? (它適用於我與海灣合作委員會,但不與「gcc -std = c99 -pedantic」。) –