簡體   English   中英

外部內聯做什么?

[英]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 是最早實現內聯的,並引入了inlinestatic inlineextern inline結構; 大多數 C99 之前的編譯器通常都跟隨它的步伐。

GNU89:

  • inline :該函數可能是內聯的(不過這只是一個提示)。 外部版本總是發出並且外部可見。 因此,您只能在一個編譯單元中定義這樣的內聯,而其他每個編譯單元都需要將其視為外聯函數(否則您將在鏈接時得到重復的符號)。
  • extern inline不會生成外extern inline版本,但可能會調用一個(因此您必須在其他編譯單元中定義它。不過,一個定義規則適用;外聯版本必須具有相同的代碼作為這里提供的內聯,以防編譯器調用它。
  • static inline不會生成外部可見的外部版本,但它可能會生成文件靜態版本。 一個定義規則不適用,因為從來沒有發出的外部符號,也沒有對一個的調用。

C99(或 GNU99):

  • inline : 像 GNU89 "extern inline"; 不發出任何外部可見的函數,但可能會被調用,因此必須存在
  • extern inline : 就像 GNU89 "inline": 發出外部可見的代碼,所以最多一個翻譯單元可以使用它。
  • static inline :像 GNU89“靜態內聯”。 這是 gnu89 和 c99 之間唯一可移植的

C++:

在任何地方內聯的函數必須在任何地方內聯,並具有相同的定義。 編譯器/鏈接器將整理出符號的多個實例。 沒有static inlineextern 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 ,它看起來大致相同,但顯然它拒絕在其他編譯器管理得很好的一些常見情況下(例如,當優化關閉時)內聯。

內聯並發出弱符號(如 C++,又名“讓它工作”)

__attribute__((weak))
void foo(void);
inline void foo(void) { ... }

請注意,這會留下一堆相同代碼的副本,鏈接器會任意選擇一個。

MSVC 在 C 模式下似乎沒有完全等效的東西,盡管有一些類似的東西。 __declspec(selectany)似乎只討論數據,所以可能不適用於函數? 還有對弱別名的鏈接器支持,但這在這里有效嗎?

內聯,但從不發出任何符號(留下外部引用)

__attribute__((gnu_inline))
extern inline void foo(void) { ... }

MSVC 的__declspec(dllimport)結合實際定義(否則不尋常),據說可以做到這一點。

總是發出(對於一個 TU,解決前面的問題)

暗示版本在 C++ 中發出一個弱符號,但在 C 的任一方言中發出一個強符號:

void foo(void);
inline void foo(void) { ... }

或者,您可以在沒有提示的情況下執行此操作,這會在兩種語言中發出強符號:

void foo(void) { ... }

通常,當您提供定義時,您知道您的 TU 是什么語言,並且可能不需要太多內聯。

MSVC 的__declspec(dllexport)據說可以做到這一點。

內聯並在每個 TU 中發出

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 中的作用的一些有用且詳細的信息。

僅限 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM