C++ extern inline 有什么作用?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/216510/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:47:46  来源:igfitidea点击:

What does extern inline do?

c++cexterninline-functions

提问by puetzk

I understand that inlineby itself is a suggestion to the compiler, and at its discretion it may or may not inline the function, and it will also produce linkable object code.

我知道这inline本身就是对编译器的建议,它可以自行决定是否内联该函数,并且它还会生成可链接的目标代码。

I think that static inlinedoes the same (may or may not inline) but will not produce linkable object code when inlined (since no other module could link to it).

我认为这样static inline做是一样的(可能会也可能不会内联),但在内联时不会产生可链接的目标代码(因为没有其他模块可以链接到它)。

Where does extern inlinefit into the picture?

哪里extern inline适合图片?

Assume I want to replace a preprocessor macro by an inline function and require that this function gets inlined (e.g., because it uses the __FILE__and __LINE__macros which should resolve for the caller but not this called function). That is, I want to see a compiler or linker error in case the function does not get inlined. Does extern inlinedo this? (I assume that, if it does not, there is no way to achieve this behavior other than sticking with a macro.)

假设我想用一个内联函数替换一个预处理器宏,并要求这个函数被内联(例如,因为它使用__FILE____LINE__宏应该为调用者解析而不是这个被调用的函数)。也就是说,如果函数没有被内联,我希望看到编译器或链接器错误。不extern inline这样做呢?(我假设,如果没有,除了坚持使用宏之外,没有办法实现这种行为。)

Are there differences between C++ and C?

C++ 和 C 之间有区别吗?

Are there differences between different compiler vendors and versions?

不同的编译器供应商和版本之间是否存在差异?

回答by puetzk

in K&R C or C89, inline was not part of the language. Many compilers implemented it as an extension, but there were no defined semantics regarding how it worked. GCC was among the first to implement inlining, and introduced the inline, static inline, and extern inlineconstructs; most pre-C99 compiler generally follow its lead.

在 K&R C 或 C89 中,内联不是语言的一部分。许多编译器将其实现为扩展,但没有关于它如何工作的定义语义。GCC是第一个实施内联外,并介绍了inlinestatic inlineextern inline构造; 大多数 C99 之前的编译器通常都跟随它的步伐。

GNU89:

GNU89:

  • inline: the function may be inlined (it's just a hint though). An out-of-line version is always emitted and externally visible. Hence you can only have such an inline defined in one compilation unit, and every other one needs to see it as an out-of-line function (or you'll get duplicate symbols at link time).
  • extern inlinewill not generate an out-of-line version, but might call one (which you therefore must define in some other compilation unit. The one-definition rule applies, though; the out-of-line version must have the same code as the inline offered here, in case the compiler calls that instead.
  • static inlinewill not generate a externally visible out-of-line version, though it might generate a file static one. The one-definition rule does not apply, since there is never an emitted external symbol nor a call to one.
  • inline:该函数可能是内联的(不过这只是一个提示)。外部版本总是发出并且外部可见。因此,您只能在一个编译单元中定义这样的内联,而其他每个编译单元都需要将其视为外联函数(否则您将在链接时得到重复的符号)。
  • extern inline不会生成外线版本,但可能会调用一个(因此您必须在其他编译单元中定义它。但是,一个定义规则适用;外线版本必须与此处提供内联,以防编译器调用它。
  • static inline不会生成外部可见的外部版本,尽管它可能会生成文件静态版本。一个定义规则不适用,因为从来没有发出的外部符号,也没有对一个的调用。

C99 (or GNU99):

C99(或 GNU99):

  • inline: like GNU89 "extern inline"; no externally visible function is emitted, but one might be called and so must exist
  • extern inline: like GNU89 "inline": externally visible code is emitted, so at most one translation unit can use this.
  • static inline: like GNU89 "static inline". This is the only portable one between gnu89 and c99
  • inline: 像 GNU89 "extern inline"; 不发出任何外部可见的函数,但可能会被调用,因此必须存在
  • extern inline: 就像 GNU89 "inline": 发出外部可见的代码,所以最多一个翻译单元可以使用它。
  • static inline:像GNU89“静态内联”。这是 gnu89 和 c99 之间唯一可移植的

C++:

C++:

A function that is inline anywhere must be inline everywhere, with the same definition. The compiler/linker will sort out multiple instances of the symbol. There is no definition of static inlineor extern inline, though many compilers have them (typically following the gnu89 model).

在任何地方内联的函数必须在任何地方内联,并具有相同的定义。编译器/链接器将整理出符号的多个实例。没有static inlineor 的定义extern inline,尽管许多编译器都有它们(通常遵循 gnu89 模型)。

回答by Don Neufeld

I believe you misunderstand __FILE__ and __LINE__ based on this statement:

我相信您根据以下声明误解了 __FILE__ 和 __LINE__:

because it uses the __FILE__ and __LINE__ macros which should resolve for the caller but not this called function

因为它使用 __FILE__ 和 __LINE__ 宏,它们应该为调用者解析,而不是这个被调用的函数

There are several phases of compilation, and preprocessing is the first. __FILE__ and __LINE__ are replaced during that phase. So by the time the compiler can consider the function for inlining they have already been replaced.

编译有几个阶段,预处理是第一个。__FILE__ 和 __LINE__ 在该阶段被替换。所以当编译器可以考虑用于内联的函数时,它们已经被替换了。

回答by Roddy

It sounds like you're trying to write something like this:

听起来你正在尝试写这样的东西:

inline void printLocation()
{
  cout <<"You're at " __FILE__ ", line number" __LINE__;
}

{
...
  printLocation();
...
  printLocation();
...
  printLocation();

and hoping that you'll get different values printed each time. As Don says, you won't, because __FILE__ and __LINE__ are implemented by the preprocessor, but inline is implemented by the compiler. So wherever you call printLocation from, you'll get the same result.

并希望您每次都能打印出不同的值。正如唐所说,你不会,因为 __FILE__ 和 __LINE__ 是由预处理器实现的,但内联是由编译器实现的。因此,无论您从何处调用 printLocation,您都会得到相同的结果。

The onlyway you can get this to work is to make printLocation a macro. (Yes, I know...)

让它工作的唯一方法是使 printLocation 成为一个宏。(是的我知道...)

#define PRINT_LOCATION  {cout <<"You're at " __FILE__ ", line number" __LINE__}

...
  PRINT_LOCATION;
...
  PRINT_LOCATION;
...

回答by Simon Howard

The situation with inline, static inline and extern inline is complicated, not least because gcc and C99 define slightly different meanings for their behavior (and presumably C++, as well). You can find some useful and detailed information about what they do in C here.

内联、静态内联和外联内联的情况很复杂,尤其是因为 gcc 和 C99 为其行为定义了略有不同的含义(大概也是 C++)。您可以在此处找到有关它们在 C 中的作用的一些有用且详细的信息。

回答by enthusiasticgeek

Macros are your choice here rather than the inline functions. A rare occasion where macros rule over inline functions. Try the following: I wrote this "MACRO MAGIC" code and it should work! Tested on gcc/g++ Ubuntu 10.04

宏是您的选择,而不是内联函数。宏统治内联函数的罕见情况。尝试以下操作:我写了这个“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;
}

For multiple files define these macros in a separate header file including the same in each c/cc/cxx/cpp files.Please prefer inline functions or const identifiers (as the case demands) over macros wherever possible.

对于多个文件,在单独的头文件中定义这些宏,包括每个 c/cc/cxx/cpp 文件中的相同内容。请尽可能使用内联函数或常量标识符(视情况而定)而不是宏。

回答by o11c

Instead of answering "what does it do?", I'm answering "how do I make it do what I want?" There are 5 kinds of inlining, all available in GNU C89, standard C99, and C++:

我不是回答“它有什么作用?”,而是回答“我如何让它做我想做的事?” 有 5 种内联,在 GNU C89、标准 C99 和 C++ 中都可用:

always inline, unless the address is taken

总是内联,除非地址被占用

Add __attribute__((always_inline))to any declaration, then use one of the below cases to handle the possibility of its address being taken.

添加__attribute__((always_inline))到任何声明,然后使用以下情况之一来处理其地址被占用的可能性。

You should probably never use this, unless you need its semantics (e.g. to affect the assembly in a certain way, or to use alloca). The compiler usually knows better than you whether it's worth it.

您可能永远不应该使用它,除非您需要它的语义(例如,以某种方式影响程序集,或使用alloca)。编译器通常比你更清楚它是否值得。

inline and emit a weak symbol (like C++, aka "just make it work")

内联并发出弱符号(如 C++,又名“让它工作”)

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

Note that this leaves a bunch of copies of the same code lying around, and the linker picks one arbitrarily.

请注意,这会留下一堆相同代码的副本,链接器会任意选择一个。

inline, but never emit any symbol (leaving external references)

内联,但从不发出任何符号(留下外部引用)

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

emit always (for one TU, to resolve the preceding)

总是发出(对于一个 TU,解决前面的问题)

The hinted version emits a weak symbol in C++, but a strong symbol in either dialect of C:

暗示版本在 C++ 中发出一个弱符号,但在 C 的任一方言中发出一个强符号:

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

Or you can do it without the hint, which emits a strong symbol in both languages:

或者,您可以在没有提示的情况下执行此操作,这会在两种语言中发出强符号:

void foo(void) { ... }

Generally, you know what language your TU is when you're providing the definitions, and probably don't need much inlining.

通常,当您提供定义时,您知道您的 TU 是什么语言,并且可能不需要太多内联。

inline and emit in every TU

内联并在每个 TU 中发出

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


For all of these except the staticone, you can add a void foo(void)declaration above. This helps with the "best practice" of writing clean headers, then #includeing a separate file with the inline definitions. Then, if using C-style inlines, #definesome macro differently in one dedicated TU to provide the out-of-line definitions.

对于除static一个之外的所有这些,您可以在void foo(void)上面添加一个声明。这有助于编写干净的标头,然后#include使用内联定义使用单独的文件的“最佳实践” 。然后,如果使用 C 样式的内联,则#define在一个专用 TU 中的某些宏会有所不同,以提供外联定义。

Don't forget extern "C"if the header might be used from both C and C++!

不要忘记extern "C"头文件是否可以从 C 和 C++ 中使用!