外部内联有什么作用?

发布于 2024-07-07 04:28:55 字数 480 浏览 9 评论 0 原文

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

我认为 static inline 的作用相同(可能是内联,也可能不是内联),但在内联时不会生成可链接的目标代码(因为没有其他模块可以链接到它)。

extern inline 适合图片中的什么位置?

假设我想用内联函数替换预处理器宏,并要求该函数被内联(例如,因为它使用 __FILE__ 和 __LINE__ 宏,这些宏应该为调用者解析但不是这个被调用的函数)。 也就是说,我希望在函数未内联的情况下看到编译器或链接器错误。 extern inline 可以做到这一点吗? (我认为,如果没有,除了坚持使用宏之外,没有其他方法可以实现这种行为。)

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

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

I understand that inline by 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.

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

Where does extern inline fit into the picture?

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 inline do this? (I assume that, if it does not, there is no way to achieve this behavior other than sticking with a macro.)

Are there differences between C++ and C?

Are there differences between different compiler vendors and versions?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

悲喜皆因你 2024-07-14 04:28:55

在 K&RC 或 C89 中,内联不是语言的一部分。 许多编译器将其实现为扩展,但没有关于其工作方式的定义语义。 GCC 是最早实现内联的国家之一,并引入了 inlinestatic inlineextern inline 结构; 大多数 C99 之前的编译器通常都会遵循它的指导。

GNU89:

  • inline:该函数可以是内联的(但这只是一个提示)。 外线版本始终会发出并且外部可见。 因此,您只能在一个编译单元中定义这样的内联函数,而其他每个编译单元都需要将其视为外联函数(否则您将在链接时获得重复的符号)。
  • extern inline 不会生成外联版本,但可能会调用一个外联版本(因此您必须在其他编译单元中定义该版本)。不过,单定义规则适用;外联版本行版本必须与此处提供的内联具有相同的代码,以防编译器调用
  • 静态内联而不会生成外部可见的外行版本,尽管它可能会生成文件静态 。一定义规则不适用,因为从来没有发出的外部符号,也没有对 1 的调用:

  • inline:像 GNU89“外部内联”一样;函数已发出,但可能会被调用,因此必须存在(根据编译器选项,编译有时可能会成功)
  • 。 >extern inline:像GNU89“inline”:发出外部可见的代码,因此最多一个翻译单元可以使用它
  • static inline:像GNU89“static inline”。 之间唯一可移植的函数

这是 gnu89 和 c99 C++

:在任何地方内联的函数必须在任何地方内联,并具有相同(完整)的定义。 编译器/链接器将整理符号的多个实例。 尽管许多编译器都有静态内联或外部内联,但没有定义它们(通常遵循 gnu89 模型)。 如果未在本地使用符号作为优化,某些编译器将忽略导出符号。

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 inline constructs; most pre-C99 compiler generally follow its lead.

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 inline will 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 inline will 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.

C99 (or GNU99):

  • inline: like GNU89 "extern inline"; no externally visible function is emitted, but one might be called and so must exist (compilation might occasionally succeed depending on compiler options).
  • 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

C++:

A function that is inline anywhere must be inline everywhere, with the same (full) definition. The compiler/linker will sort out multiple instances of the symbol. There is no definition of static inline or extern inline, though many compilers have them (typically following the gnu89 model). Some compilers will omit exporting the symbol if it isn't used locally as an optimization.

邮友 2024-07-14 04:28:55

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

因为它使用 __FILE__ 和
__LINE__ 宏应该为调用者解析,但不是这个调用
功能

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

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

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

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.

我的影子我的梦 2024-07-14 04:28:55

听起来您正在尝试编写这样的内容:

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

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

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

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

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

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

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.

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

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

...
  PRINT_LOCATION;
...
  PRINT_LOCATION;
...
原来分手还会想你 2024-07-14 04:28:55

我不是回答“它有什么作用?”,而是回答“我如何让它做我想做的事?” 内联有 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)[[msvc::noinline]] 但它被记录为仅适用于成员函数。 但是,我看到提到“安全属性”可能会阻止内联?

如果可能的话,强制将其他函数内联到此函数中。

将 __attribute__((flatten)) 添加到函数的任何声明中。

请注意,noinline 比这更强大(未在 MSVC 上测试),其定义在编译时未知的函数也是如此。

MSVC 现在记录 [[msvc: :压平]]; 请注意,它适用于范围而不是函数。 以前没有等效项,因为 [[msvc::forceinline_calls]] 不是递归的。

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++. MSVC has some of them (note that I haven't tested the MSVC code)

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.

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.

MSVC has __forceinline which appears mostly the same, but apparently it refuses to inline in quite a few common circumstances (e.g. when optimization is off) where other compilers manage just fine.

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

__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.

MSVC doesn't appear to have an exact equivalent in C mode, although there are a couple of similar things. __declspec(selectany) appears to be talking about data only, so might not apply to functions? There is also linker support for weak aliases, but does that work here?

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

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

MSVC's __declspec(dllimport), combined with an actual definition (otherwise unusual), supposedly does this.

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

The hinted version emits a weak symbol in C++, but a strong symbol in either dialect of 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.

MSVC's __declspec(dllexport) supposedly does this.

inline and emit in every TU

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

For all of these except the static one, 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, #define some macro differently in one dedicated TU to provide the out-of-line definitions.

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


There are also a couple of related things:

never inline

Add __attribute__((noinline)) to any declaration of the function.

MSVC has __declspec(noinline) and [[msvc::noinline]] but it is documented to only work for member functions. However, I've seen mention of "security attributes" which might prevent inlining?

force other functions to be inlined into this one if possible.

Add __attribute__((flatten)) to any declaration of the function.

Note that noinline is more powerful than this (not tested on MSVC), as are functions whose definition isn't known at compile-time.

MSVC now documents [[msvc::flatten]]; note that it applies to a scope rather than to a function. Formerly there was no equivalent, since [[msvc::forceinline_calls]] is not recursive.

假装不在乎 2024-07-14 04:28:55

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

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.

二手情话 2024-07-14 04:28:55

在这里您可以选择宏而不是内联函数。 宏统治内联函数的罕见情况。 尝试以下操作:我编写了这个“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 文件中的相同宏。 请优先使用内联函数或 const 标识符(视情况而定)要求)尽可能超过宏。

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

//(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.

寄离 2024-07-14 04:28:55

仅限 C++:

正如其他人指出的那样,宏(此处为 __FILE__ 和 __LINE__ )在编译和链接之前进行评估; 因此,如果您有一个使用这些函数的函数,并且希望每个文件的函数都不同,则需要与内联相反的函数。 由于每个文件的 __FILE__ 和 __LINE__ 值都不同,因此每个文件的函数定义(主体)也将不同。 但是(非静态)inline 意味着如果函数在多个翻译单元中定义,它们都必须具有相同的定义

您可以在头文件中定义(而不是声明)普通函数或staticstatic inline 函数,并将其包含在您想要的任何位置。 这样,每个翻译单元(源文件)都会获得自己的具有不同 __FILE____LINE__ 值的函数副本。 虽然,我认为在static inline的情况下,inline关键字在大多数情况下是没有用的。

C++ only:

As others have pointed out, macros (here __FILE__ and __LINE__) are evaluated before compiling and linking; So if you have a function that uses those and you want them to be different for each file, you need the opposite of inline. Since the __FILE__ and __LINE__ values are going to be different for each file, then the definition (body) of the function is going to be different for each file. But (non-static) inline means that if the function is defined in multiple translation units, they all must have the same definition.

You could define (not declare) a normal function or static or static inline function in a header file and include it anywhere you want. This way each translation unit (source file) gets its own copy of the function with different __FILE__ and __LINE__ values. Although, I think in the case of static inline, the inline keyword is useless in most cases.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文