[英]What does extern inline do?
我知道inline
本身是對編譯器的建議,它可能會或可能不會內聯 function,它還會生成可鏈接的 object 代碼。
我認為static inline
執行相同的操作(可能內聯也可能不內聯),但內聯時不會產生可鏈接的 object 代碼(因為沒有其他模塊可以鏈接到它)。
extern inline
在哪里適合圖片?
假設我想用內聯 function 替換預處理器宏,並要求這個 function 被內聯(例如,因為它使用__FILE__
和__LINE__
宏,它們應該為調用者而不是這個被調用函數解析)。 也就是說,如果 function 沒有內聯,我想查看編譯器或 linker 錯誤。 extern inline
會這樣做嗎? (我認為,如果沒有,除了堅持使用宏之外,沒有其他方法可以實現這種行為。)
C++和C有區別嗎?
不同的編譯器供應商和版本之間是否存在差異?
在 K&R C 或 C89 中,內聯不是語言的一部分。 許多編譯器將其實現為擴展,但沒有關於它如何工作的定義語義。 GCC 是最早實現內聯的,並引入了inline
、 static inline
和extern inline
結構; 大多數 C99 之前的編譯器通常都跟隨它的步伐。
inline
:該函數可能是內聯的(不過這只是一個提示)。 外部版本總是發出並且外部可見。 因此,您只能在一個編譯單元中定義這樣的內聯,而其他每個編譯單元都需要將其視為外聯函數(否則您將在鏈接時得到重復的符號)。extern inline
不會生成外extern inline
版本,但可能會調用一個(因此您必須在其他編譯單元中定義它。不過,一個定義規則適用;外聯版本必須具有相同的代碼作為這里提供的內聯,以防編譯器調用它。static inline
不會生成外部可見的外部版本,但它可能會生成文件靜態版本。 一個定義規則不適用,因為從來沒有發出的外部符號,也沒有對一個的調用。inline
: 像 GNU89 "extern inline"; 不發出任何外部可見的函數,但可能會被調用,因此必須存在extern inline
: 就像 GNU89 "inline": 發出外部可見的代碼,所以最多一個翻譯單元可以使用它。static inline
:像 GNU89“靜態內聯”。 這是 gnu89 和 c99 之間唯一可移植的 在任何地方內聯的函數必須在任何地方內聯,並具有相同的定義。 編譯器/鏈接器將整理出符號的多個實例。 沒有static inline
或extern inline
定義,盡管許多編譯器都有它們(通常遵循 gnu89 模型)。
我相信您根據以下聲明誤解了 __FILE__ 和 __LINE__:
因為它使用 __FILE__ 和 __LINE__ 宏,它們應該為調用者解析,而不是這個被調用的函數
編譯有幾個階段,預處理是第一個。 __FILE__ 和 __LINE__ 在該階段被替換。 所以當編譯器可以考慮用於內聯的函數時,它們已經被替換了。
聽起來你正在嘗試寫這樣的東西:
inline void printLocation()
{
cout <<"You're at " __FILE__ ", line number" __LINE__;
}
{
...
printLocation();
...
printLocation();
...
printLocation();
並希望您每次都能打印出不同的值。 正如唐所說,你不會,因為 __FILE__ 和 __LINE__ 是由預處理器實現的,但內聯是由編譯器實現的。 因此,無論您從何處調用 printLocation,您都會得到相同的結果。
讓它工作的唯一方法是使 printLocation 成為一個宏。 (是的,我知道...)
#define PRINT_LOCATION {cout <<"You're at " __FILE__ ", line number" __LINE__}
...
PRINT_LOCATION;
...
PRINT_LOCATION;
...
我不是回答“它有什么作用?”,而是回答“我如何讓它做我想做的事?” 有 5 種內聯,在 GNU C89、標准 C99 和 C++ 中都可用。 MSVC 有一些(請注意,我還沒有測試 MSVC 代碼)
將__attribute__((always_inline))
添加到任何聲明中,然后使用以下情況之一來處理其地址被占用的可能性。
您可能永遠不應該使用它,除非您需要它的語義(例如,以某種方式影響程序集,或使用alloca
)。 編譯器通常比你更清楚它是否值得。
MSVC 有__forceinline
,它看起來大致相同,但顯然它拒絕在其他編譯器管理得很好的一些常見情況下(例如,當優化關閉時)內聯。
__attribute__((weak))
void foo(void);
inline void foo(void) { ... }
請注意,這會留下一堆相同代碼的副本,鏈接器會任意選擇一個。
MSVC 在 C 模式下似乎沒有完全等效的東西,盡管有一些類似的東西。 __declspec(selectany)
似乎只討論數據,所以可能不適用於函數? 還有對弱別名的鏈接器支持,但這在這里有效嗎?
__attribute__((gnu_inline))
extern inline void foo(void) { ... }
MSVC 的__declspec(dllimport)
結合實際定義(否則不尋常),據說可以做到這一點。
暗示版本在 C++ 中發出一個弱符號,但在 C 的任一方言中發出一個強符號:
void foo(void);
inline void foo(void) { ... }
或者,您可以在沒有提示的情況下執行此操作,這會在兩種語言中發出強符號:
void foo(void) { ... }
通常,當您提供定義時,您知道您的 TU 是什么語言,並且可能不需要太多內聯。
MSVC 的__declspec(dllexport)
據說可以做到這一點。
static inline void foo(void) { ... }
對於除static
之外的所有這些,您可以在上面添加一個void foo(void)
聲明。 這有助於編寫干凈的標題的“最佳實踐”,然后#include
使用內聯定義單獨的文件。 然后,如果使用 C 風格的內聯,在一個專用 TU 中#define
一些不同的宏以提供外聯定義。
如果頭文件可以從 C 和 C++ 中使用,請不要忘記extern "C"
!
還有一些相關的事情:
將__attribute__((noinline))
到函數的任何聲明中。
MSVC 有__declspec(noinline)
但它被記錄為僅適用於成員函數。 但是,我已經看到提到可能會阻止內聯的“安全屬性”?
將__attribute__((flatten))
到函數的任何聲明中。
請注意, noinline
比這更強大,其定義在編譯時未知的函數也是如此。
MSVC 似乎沒有等價物。 我見過一次提到[[msvc::forceinline_calls]]
(應用於語句或塊),但它不是遞歸的。
宏是您的選擇,而不是內聯函數。 宏統治內聯函數的罕見情況。 嘗試以下操作:我寫了這個“MACRO MAGIC”代碼,它應該可以工作! 在 gcc/g++ Ubuntu 10.04 上測試
//(c) 2012 enthusiasticgeek (LOGGING example for StackOverflow)
#ifdef __cplusplus
#include <cstdio>
#include <cstring>
#else
#include <stdio.h>
#include <string.h>
#endif
//=========== MACRO MAGIC BEGINS ============
//Trim full file path
#define __SFILE__ (strrchr(__FILE__,'/') ? strrchr(__FILE__,'/')+1 : __FILE__ )
#define STRINGIFY_N(x) #x
#define TOSTRING_N(x) STRINGIFY_N(x)
#define _LINE (TOSTRING_N(__LINE__))
#define LOG(x, s...) printf("(%s:%s:%s)" x "\n" , __SFILE__, __func__, _LINE, ## s);
//=========== MACRO MAGIC ENDS ============
int main (int argc, char** argv) {
LOG("Greetings StackOverflow! - from enthusiasticgeek\n");
return 0;
}
對於多個文件,在單獨的頭文件中定義這些宏,包括每個 c/cc/cxx/cpp 文件中的相同內容。 請盡可能使用內聯函數或常量標識符(視情況而定)而不是宏。
內聯、靜態內聯和外聯內聯的情況很復雜,尤其是因為 gcc 和 C99 為其行為定義了略有不同的含義(大概也是 C++)。 您可以在此處找到有關它們在 C 中的作用的一些有用且詳細的信息。
正如其他人指出的那樣,宏(此處為__FILE__
和__LINE__
)在編譯和鏈接之前進行評估; 因此,如果您有一個使用它們的 function 並且您希望它們對於每個文件都不同,那么您需要與inline
相反。 由於每個文件的__FILE__
和__LINE__
值將不同,因此每個文件的 function 的定義(主體)將不同。 但是(非靜態) inline
意味着如果 function 在多個翻譯單元中定義,則所有翻譯單元必須具有相同的定義。
You could define (not declare) a normal function or static
or static inline
function in a header file and include it anywhere you want. 這樣,每個翻譯單元(源文件)都會獲得自己的 function 副本,其中__FILE__
和__LINE__
值不同。 雖然,我認為在static inline
的情況下, inline
關鍵字在大多數情況下是無用的。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.