[英]What does extern inline do?
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.我知道
inline
本身是对编译器的建议,它可能会或可能不会内联 function,它还会生成可链接的 object 代码。
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).我认为
static inline
执行相同的操作(可能内联也可能不内联),但内联时不会产生可链接的 object 代码(因为没有其他模块可以链接到它)。
Where does extern inline
fit into the picture? extern inline
在哪里适合图片?
Assume I want to replace a preprocessor macro by an inline function and require that this function gets inlined (eg, because it uses the __FILE__
and __LINE__
macros which should resolve for the caller but not this called function).假设我想用内联 function 替换预处理器宏,并要求这个 function 被内联(例如,因为它使用
__FILE__
和__LINE__
宏,它们应该为调用者而不是这个被调用函数解析)。 That is, I want to see a compiler or linker error in case the function does not get inlined.也就是说,如果 function 没有内联,我想查看编译器或 linker 错误。 Does
extern inline
do this? extern inline
会这样做吗? (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? C++和C有区别吗?
Are there differences between different compiler vendors and versions?不同的编译器供应商和版本之间是否存在差异?
in K&R C or C89, inline was not part of the language.在 K&R C 或 C89 中,内联不是语言的一部分。 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; GCC 是最早实现内联的,并引入了
inline
、 static inline
和extern inline
结构; most pre-C99 compiler generally follow its lead.大多数 C99 之前的编译器通常都跟随它的步伐。
inline
: the function may be inlined (it's just a hint though). inline
:该函数可能是内联的(不过这只是一个提示)。 An out-of-line version is always emitted and externally visible.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. extern inline
不会生成外extern inline
版本,但可能会调用一个(因此您必须在其他编译单元中定义它。不过,一个定义规则适用;外联版本必须具有相同的代码作为这里提供的内联,以防编译器调用它。static inline
will not generate a externally visible out-of-line version, though it might generate a file static one. static inline
不会生成外部可见的外部版本,但它可能会生成文件静态版本。 The one-definition rule does not apply, since there is never an emitted external symbol nor a call to one.inline
: like GNU89 "extern inline"; inline
: 像 GNU89 "extern inline"; no externally visible function is emitted, but one might be called and so must existextern inline
: like GNU89 "inline": externally visible code is emitted, so at most one translation unit can use this. extern inline
: 就像 GNU89 "inline": 发出外部可见的代码,所以最多一个翻译单元可以使用它。static inline
: like GNU89 "static inline". static inline
:像 GNU89“静态内联”。 This is the only portable one between gnu89 and c99 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 inline
or extern inline
, though many compilers have them (typically following the gnu89 model).没有
static inline
或extern inline
定义,尽管许多编译器都有它们(通常遵循 gnu89 模型)。
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.
__FILE__ 和 __LINE__ 在该阶段被替换。 So by the time the compiler can consider the function for inlining they have already been replaced.
所以当编译器可以考虑用于内联的函数时,它们已经被替换了。
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.
正如唐所说,你不会,因为 __FILE__ 和 __LINE__ 是由预处理器实现的,但内联是由编译器实现的。 So wherever you call printLocation from, you'll get the same result.
因此,无论您从何处调用 printLocation,您都会得到相同的结果。
The only way you can get this to work is to make printLocation a macro.让它工作的唯一方法是使 printLocation 成为一个宏。 (Yes, I know...)
(是的,我知道...)
#define PRINT_LOCATION {cout <<"You're at " __FILE__ ", line number" __LINE__}
...
PRINT_LOCATION;
...
PRINT_LOCATION;
...
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++ 中都可用。 MSVC has some of them (note that I haven't tested the MSVC code)
MSVC 有一些(请注意,我还没有测试 MSVC 代码)
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 (eg to affect the assembly in a certain way, or to use alloca
).您可能永远不应该使用它,除非您需要它的语义(例如,以某种方式影响程序集,或使用
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 (eg when optimization is off) where other compilers manage just fine. MSVC 有
__forceinline
,它看起来大致相同,但显然它拒绝在其他编译器管理得很好的一些常见情况下(例如,当优化关闭时)内联。
__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. MSVC 在 C 模式下似乎没有完全等效的东西,尽管有一些类似的东西。
__declspec(selectany)
appears to be talking about data only, so might not apply to functions? __declspec(selectany)
似乎只讨论数据,所以可能不适用于函数? There is also linker support for weak aliases , but does that work here?还有对弱别名的链接器支持,但这在这里有效吗?
__attribute__((gnu_inline))
extern inline void foo(void) { ... }
MSVC's __declspec(dllimport)
, combined with an actual definition (otherwise unusual), supposedly does this. MSVC 的
__declspec(dllimport)
结合实际定义(否则不寻常),据说可以做到这一点。
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 是什么语言,并且可能不需要太多内联。
MSVC's __declspec(dllexport)
supposedly does this. MSVC 的
__declspec(dllexport)
据说可以做到这一点。
static inline void foo(void) { ... }
For all of these except the static
one, you can add a void foo(void)
declaration above.对于除
static
之外的所有这些,您可以在上面添加一个void foo(void)
声明。 This helps with the "best practice" of writing clean headers, then #include
ing a separate file with the inline definitions.这有助于编写干净的标题的“最佳实践”,然后
#include
使用内联定义单独的文件。 Then, if using C-style inlines, #define
some macro differently in one dedicated TU to provide the out-of-line definitions.然后,如果使用 C 风格的内联,在一个专用 TU 中
#define
一些不同的宏以提供外联定义。
Don't forget extern "C"
if the header might be used from both C and C++!如果头文件可以从 C 和 C++ 中使用,请不要忘记
extern "C"
!
There are also a couple of related things:还有一些相关的事情:
Add __attribute__((noinline))
to any declaration of the function.将
__attribute__((noinline))
到函数的任何声明中。
MSVC has __declspec(noinline)
but it is documented to only work for member functions. MSVC 有
__declspec(noinline)
但它被记录为仅适用于成员函数。 However, I've seen mention of "security attributes" which might prevent inlining?但是,我已经看到提到可能会阻止内联的“安全属性”?
Add __attribute__((flatten))
to any declaration of the function.将
__attribute__((flatten))
到函数的任何声明中。
Note that noinline
is more powerful than this, as are functions whose definition isn't known at compile-time.请注意,
noinline
比这更强大,其定义在编译时未知的函数也是如此。
MSVC doesn't appear to have an equivalent. MSVC 似乎没有等价物。 I've seen a single mention of
[[msvc::forceinline_calls]]
(applied to a statement or block), but it's not recursive.我见过一次提到
[[msvc::forceinline_calls]]
(应用于语句或块),但它不是递归的。
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!
尝试以下操作:我写了这个“MACRO MAGIC”代码,它应该可以工作! Tested on gcc/g++ Ubuntu 10.04
在 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.对于多个文件,在单独的头文件中定义这些宏,包括每个 c/cc/cxx/cpp 文件中的相同内容。 Please prefer inline functions or const identifiers (as the case demands) over macros wherever possible.
请尽可能使用内联函数或常量标识符(视情况而定)而不是宏。
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).内联、静态内联和外联内联的情况很复杂,尤其是因为 gcc 和 C99 为其行为定义了略有不同的含义(大概也是 C++)。 You can find some useful and detailed information about what they do in C here .
您可以在此处找到有关它们在 C 中的作用的一些有用且详细的信息。
As others have pointed out, macros (here __FILE__
and __LINE__
) are evaluated before compiling and linking;正如其他人指出的那样,宏(此处为
__FILE__
和__LINE__
)在编译和链接之前进行评估; 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
.因此,如果您有一个使用它们的 function 并且您希望它们对于每个文件都不同,那么您需要与
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.由于每个文件的
__FILE__
和__LINE__
值将不同,因此每个文件的 function 的定义(主体)将不同。 But (non-static) inline
means that if the function is defined in multiple translation units, the all must have the same definition.但是(非静态)
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. 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.这样,每个翻译单元(源文件)都会获得自己的 function 副本,其中
__FILE__
和__LINE__
值不同。 Although, I think in the case of static inline
, the inline
keyword is useless in most cases.虽然,我认为在
static inline
的情况下, inline
关键字在大多数情况下是无用的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.