内联函数有什么好处?

发布于 2024-07-07 09:25:22 字数 128 浏览 10 评论 0原文

在 C++ 中使用内联函数的优点/缺点是什么? 我发现它只会提高编译器输出的代码的性能,但是有了当今优化的编译器、快速的 CPU、巨大的内存等(不像 1980 年那样,内存稀缺,所有东西都必须放入 100KB 内存中)他们今天真的有优势吗?

What is the advantages/disadvantages of using inline functions in C++? I see that it only increases performance for the code that the compiler outputs, but with today's optimized compilers, fast CPUs, huge memory etc. (not like in the 1980< where memory was scarce and everything had to fit in 100KB of memory) what advantages do they really have today?

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

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

发布评论

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

评论(14

箹锭⒈辈孓 2024-07-14 09:25:22

优点

  • 通过在需要的地方内联代码,您的程序将在函数调用和返回部分花费更少的时间。 它应该让你的代码运行得更快,即使它变得更大(见下文)。 内联普通访问器可能是有效内联的一个例子。
  • 通过将其标记为内联,您可以将函数定义放在头文件中(即它可以包含在多个编译单元中,而不会引起链接器抱怨)

缺点

  • 它可以使您的代码更大(即如果您将内联用于不平凡的函数)。 因此,它可能会引发分页并破坏编译器的优化。
  • 它会稍微破坏您的封装,因为它暴露了对象处理的内部(但是每个“私有”成员也会暴露)。 这意味着您不得在 PImpl 模式中使用内联。
  • 它稍微破坏了你的封装 2:C++ 内联在编译时解决。 这意味着如果您更改内联函数的代码,则需要重新编译使用它的所有代码以确保它将被更新(出于同样的原因,我避免函数参数的默认值)
  • 当在标头中使用时,它使你的头文件更大,因此,会用用户不关心的代码稀释有趣的信息(例如类方法的列表)(这就是我在类中声明内联函数的原因,但会定义它在类主体之后的标头中,而不是在类主体内部)。

内联魔法

  • 编译器可能会也可能不会内联您标记为内联的函数; 它还可能决定内联在编译或链接时未标记为内联的函数。
  • 内联的工作方式就像由编译器控制的复制/粘贴,这与预处理器宏有很大不同:宏将被强制内联,会污染所有命名空间和代码,不会轻易调试,甚至会完成如果编译器认为它效率低下。
  • 在类本身的主体内定义的类的每个方法都被视为“内联”(即使编译器仍然可以决定不内联它)
  • 虚拟方法不应该是内联的。尽管如此,有时编译器可以知道确保对象的类型(即对象在同一函数体内声明和构造),即使是虚函数也会被内联,因为编译器确切地知道对象的类型
  • 模板方法/函数并不总是内联的(它们的存在) 。在标头中不会使它们自动内联)。
  • “内联”之后的下一步是模板元编程,即通过在编译时“内联”代码,编译器有时可以推断出函数的最终结果......复杂的算法有时可以简化为一种 return 42 ; 语句,这对我来说是极端内联,这在现实生活中很少发生,它会使编译时间更长。不会让你的代码变得臃肿,并且会让你的代码更快。 但就像圣杯一样,不要尝试将它应用到任何地方,因为大多数处理都无法通过这种方式解决...不过,无论如何,这很酷...
    :-p

Advantages

  • By inlining your code where it is needed, your program will spend less time in the function call and return parts. It is supposed to make your code go faster, even as it goes larger (see below). Inlining trivial accessors could be an example of effective inlining.
  • By marking it as inline, you can put a function definition in a header file (i.e. it can be included in multiple compilation unit, without the linker complaining)

Disadvantages

  • It can make your code larger (i.e. if you use inline for non-trivial functions). As such, it could provoke paging and defeat optimizations from the compiler.
  • It slightly breaks your encapsulation because it exposes the internal of your object processing (but then, every "private" member would, too). This means you must not use inlining in a PImpl pattern.
  • It slightly breaks your encapsulation 2: C++ inlining is resolved at compile time. Which means that should you change the code of the inlined function, you would need to recompile all the code using it to be sure it will be updated (for the same reason, I avoid default values for function parameters)
  • When used in a header, it makes your header file larger, and thus, will dilute interesting informations (like the list of a class methods) with code the user don't care about (this is the reason that I declare inlined functions inside a class, but will define it in an header after the class body, and never inside the class body).

Inlining Magic

  • The compiler may or may not inline the functions you marked as inline; it may also decide to inline functions not marked as inline at compilation or linking time.
  • Inline works like a copy/paste controlled by the compiler, which is quite different from a pre-processor macro: The macro will be forcibly inlined, will pollute all the namespaces and code, won't be easily debuggable, and will be done even if the compiler would have ruled it as inefficient.
  • Every method of a class defined inside the body of the class itself is considered as "inlined" (even if the compiler can still decide to not inline it
  • Virtual methods are not supposed to be inlinable. Still, sometimes, when the compiler can know for sure the type of the object (i.e. the object was declared and constructed inside the same function body), even a virtual function will be inlined because the compiler knows exactly the type of the object.
  • Template methods/functions are not always inlined (their presence in an header will not make them automatically inline).
  • The next step after "inline" is template metaprograming . I.e. By "inlining" your code at compile time, sometimes, the compiler can deduce the final result of a function... So a complex algorithm can sometimes be reduced to a kind of return 42 ; statement. This is for me extreme inlining. It happens rarely in real life, it makes compilation time longer, will not bloat your code, and will make your code faster. But like the grail, don't try to apply it everywhere because most processing cannot be resolved this way... Still, this is cool anyway...
    :-p
楠木可依 2024-07-14 09:25:22

内联函数速度更快,因为您不需要将参数和返回地址等内容推入/弹出堆栈; 但是,它确实会使您的二进制文件稍大一些。

它有显着差异吗? 对于大多数人来说,在现代硬件上还不够明显。 但它可以带来改变,这对某些人来说已经足够了。

将某些内容标记为内联并不能保证它会内联。 这只是给编译器的一个建议。 有时这是不可能的,例如当您有虚函数或涉及递归时。 有时编译器只是选择不使用它。

我可以看到这样的情况会产生明显的差异:

inline int aplusb_pow2(int a, int b) {
  return (a + b)*(a + b) ;
}

for(int a = 0; a < 900000; ++a)
    for(int b = 0; b < 900000; ++b)
        aplusb_pow2(a, b);

Inline functions are faster because you don't need to push and pop things on/off the stack like parameters and the return address; however, it does make your binary slightly larger.

Does it make a significant difference? Not noticeably enough on modern hardware for most. But it can make a difference, which is enough for some people.

Marking something inline does not give you a guarantee that it will be inline. It's just a suggestion to the compiler. Sometimes it's not possible such as when you have a virtual function, or when there is recursion involved. And sometimes the compiler just chooses not to use it.

I could see a situation like this making a detectable difference:

inline int aplusb_pow2(int a, int b) {
  return (a + b)*(a + b) ;
}

for(int a = 0; a < 900000; ++a)
    for(int b = 0; b < 900000; ++b)
        aplusb_pow2(a, b);
丘比特射中我 2024-07-14 09:25:22

在古老的 C 和 C++ 中,inline 就像 register:向编译器提供关于可能的优化的建议(只不过是建议)。

在现代 C++ 中,inline 告诉链接器,如果在不同的翻译单元中找到多个定义(而不是声明),那么它们都是相同的,链接器可以自由保留一个并丢弃所有其他定义。

如果在头文件中定义了一个函数(无论多么复杂或“线性”),则 inline 是必需的,以允许多个源包含该函数,而不会导致链接器出现“多重定义”错误。

默认情况下,类内部定义的成员函数是“内联”的,模板函数也是如此(与全局函数相反)。

//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }

//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }

//main.cpp
#include "fileA.h"
void acall();

int main()
{ 
   afunc(); 
   acall();
}

//output
this is afunc
this is afunc

请注意,将 fileA.h 包含到两个 .cpp 文件中,从而产生两个 afunc() 实例。
链接器将丢弃其中之一。
如果没有指定inline,链接器将会抱怨。

In archaic C and C++, inline is like register: a suggestion (nothing more than a suggestion) to the compiler about a possible optimization.

In modern C++, inline tells the linker that, if multiple definitions (not declarations) are found in different translation units, they are all the same, and the linker can freely keep one and discard all the other ones.

inline is mandatory if a function (no matter how complex or "linear") is defined in a header file, to allow multiple sources to include it without getting a "multiple definition" error by the linker.

Member functions defined inside a class are "inline" by default, as are template functions (in contrast to global functions).

//fileA.h
inline void afunc()
{ std::cout << "this is afunc" << std::endl; }

//file1.cpp
#include "fileA.h"
void acall()
{ afunc(); }

//main.cpp
#include "fileA.h"
void acall();

int main()
{ 
   afunc(); 
   acall();
}

//output
this is afunc
this is afunc

Note the inclusion of fileA.h into two .cpp files, resulting in two instances of afunc().
The linker will discard one of them.
If no inline is specified, the linker will complain.

煮酒 2024-07-14 09:25:22

内联是给编译器的一个建议,编译器可以忽略它。 它非常适合小段代码。

如果您的函数是内联的,它基本上会插入到对其进行函数调用的代码中,而不是实际调用单独的函数。 这可以提高速度,因为您不必进行实际的呼叫。

它还可以帮助 CPU 进行流水线操作,因为它们不必使用由调用引起的新指令重新加载流水线。

唯一的缺点是可能会增加二进制大小,但是只要函数很小,这就不会有太大影响。

如今,我倾向于将此类决定留给编译器(无论如何,都是聪明的编译器)。 编写它们的人往往对底层架构有更详细的了解。

Inlining is a suggestion to the compiler which it is free to ignore. It's ideal for small bits of code.

If your function is inlined, it's basically inserted in the code where the function call is made to it, rather than actually calling a separate function. This can assist with speed as you don't have to do the actual call.

It also assists CPUs with pipelining as they don't have to reload the pipeline with new instructions caused by a call.

The only disadvantage is possible increased binary size but, as long as the functions are small, this won't matter too much.

I tend to leave these sorts of decisions to the compilers nowadays (well, the smart ones anyway). The people who wrote them tend to have far more detailed knowledge of the underlying architectures.

很糊涂小朋友 2024-07-14 09:25:22

内联函数是编译器使用的优化技术。 我们可以简单地在函数原型前面添加 inline 关键字来使函数内联。 内联函数指示编译器在代码中使用该函数的任何位置插入该函数的完整主体。

优点:-< /strong>

  1. 它不需要函数调用开销。

  2. 它还节省了函数调用时变量入栈/出栈的开销。

  3. 它还节省了函数返回调用的开销。

  4. 它通过利用指令缓存来增加引用的局部性。

  5. 如果指定的话,内联编译器还可以应用程序内优化。 这是最重要的,这样编译器现在可以专注于死代码消除,可以更加注重分支预测、归纳变量消除等。

要查看更多信息,可以点击此链接
http://tajendrasengar.blogspot.com/2010 /03/what-is-inline-function-in-cc.html

Inline function is the optimization technique used by the compilers. One can simply prepend inline keyword to function prototype to make a function inline. Inline function instruct compiler to insert complete body of the function wherever that function got used in code.

Advantages :-

  1. It does not require function calling overhead.

  2. It also save overhead of variables push/pop on the stack, while function calling.

  3. It also save overhead of return call from a function.

  4. It increases locality of reference by utilizing instruction cache.

  5. After in-lining compiler can also apply intra-procedural optimization if specified. This is the most important one, in this way compiler can now focus on dead code elimination, can give more stress on branch prediction, induction variable elimination etc..

To check more about it one can follow this link
http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html

那些过往 2024-07-14 09:25:22

我想补充一点,当您构建共享库时,内联函数至关重要。 如果不标记函数内联,它将以二进制形式导出到库中。 如果导出的话,它也会出现在符号表中。 另一方面,内联函数不会导出,既不会导出到库二进制文件,也不会导出到符号表。

当打算在运行时加载库时,这可能很重要。 它还可能会影响二进制兼容感知库。 在这种情况下,不要使用内联。

I'd like to add that inline functions are crucial when you are building shared library. Without marking function inline, it will be exported into the library in the binary form. It will be also present in the symbols table, if exported. On the other side, inlined functions are not exported, neither to the library binaries nor to the symbols table.

It may be critical when library is intended to be loaded at runtime. It may also hit binary-compatible-aware libraries. In such cases don't use inline.

不一样的天空 2024-07-14 09:25:22

inline 允许您将函数定义放置在头文件中,并#include 该头文件放置在多个源文件中,而不会违反单一定义规则。

inline allows you to place a function definition in a header file and #include that header file in multiple source files without violating the one definition rule.

吲‖鸣 2024-07-14 09:25:22

在优化期间,许多编译器将内联函数,即使您没有标记它们。 通常,如果您知道编译器不知道的内容,则只需将函数标记为内联,因为它通常可以自行做出正确的决定。

During optimization many compilers will inline functions even if you didn't mark them. You generally only need to mark functions as inline if you know something the compiler doesn't, as it can usually make the correct decision itself.

烧了回忆取暖 2024-07-14 09:25:22

一般来说,现在任何现代编译器担心内联任何东西几乎都是浪费时间。 编译器实际上应该通过自己对代码的分析以及传递给编译器的优化标志的规范来为您优化所有这些注意事项。 如果您关心速度,请告诉编译器优化速度。 如果您关心空间,请告诉编译器优化空间。 正如另一个答案所提到的,如果确实有意义,一个像样的编译器甚至会自动内联。

此外,正如其他人所说,使用内联并不能保证任何内容的内联。 如果你想保证它,你必须定义一个宏而不是一个内联函数来做到这一点。

何时内联和/或定义宏以强制包含? - 仅当已知对应用程序整体性能有影响的代码关键部分的速度已得到证明且必要时得到证实。

Generally speaking, these days with any modern compiler worrying about inlining anything is pretty much a waste of time. The compiler should actually optimize all of these considerations for you through its own analysis of the code and your specification of the optimization flags passed to the compiler. If you care about speed, tell the compiler to optimize for speed. If you care about space, tell the compiler to optimize for space. As another answer alluded to, a decent compiler will even inline automatically if it really makes sense.

Also, as others have stated, using inline does not guarantee inline of anything. If you want to guarantee it, you will have to define a macro instead of an inline function to do it.

When to inline and/or define a macro to force inclusion? - Only when you have a demonstrated and necessary proven increase in speed for a critical section of code that is known to have an affect on the overall performance of the application.

绳情 2024-07-14 09:25:22

这不仅仅与性能有关。 C++ 和 C 都用于嵌入式编程,位于硬件之上。 例如,如果您要编写一个中断处理程序,则需要确保代码可以立即执行,而无需交换额外的寄存器和/或内存页。 这就是内联派上用场的时候。 当需要速度时,好的编译器会自行进行一些“内联”,但“内联”迫使它们这样做。

It is not all about performance. Both C++ and C are used for embedded programming, sitting on top of hardware. If you would, for example, write an interrupt handler, you need to make sure that the code can be executed at once, without additional registers and/or memory pages being being swapped. That is when inline comes in handy. Good compilers do some "inlining" themselves when speed is needed, but "inline" compels them.

像极了他 2024-07-14 09:25:22

将函数内联到 so 库中也遇到了同样的麻烦。 看来内联函数没有编译到库中。 因此,如果可执行文件想要使用库的内联函数,链接器会发出“未定义的引用”错误。 (发生在我用 gcc 4.5 编译 Qt 源代码时。

Fell into the same trouble with inlining functions into so libraries. It seems that inlined functions are not compiled into the library. as a result the linker puts out a "undefined reference" error, if a executable wants to use the inlined function of the library. (happened to me compiling Qt source with gcc 4.5.

梦开始←不甜 2024-07-14 09:25:22

为什么不默认将所有函数设置为内联? 因为这是一个工程权衡。 至少有两种类型的“优化”:加速程序和减少程序的大小(内存占用)。 内联通常会加快速度。 它消除了函数调用开销,避免了从堆栈中推入然后拉出参数。 然而,它也使程序的内存占用更大,因为现在每个函数调用都必须替换为函数的完整代码。 让事情变得更加复杂的是,请记住 CPU 将经常使用的内存块存储在 CPU 的缓存中,以实现超快速访问。 如果您使程序的内存映像足够大,您的程序将无法有效地使用缓存,并且在最坏的情况下,内联实际上可能会减慢您的程序速度。 在某种程度上,编译器可以计算出权衡是什么,并且可能比您仅查看源代码做出更好的决策。

Why not make all functions inline by default? Because it's an engineering trade off. There are at least two types of "optimization": speeding up the program and reducing the size (memory footprint) of the program. Inlining generally speeds things up. It gets rid of the function call overhead, avoiding pushing then pulling parameters from the stack. However, it also makes the memory footprint of the program bigger, because every function call must now be replaced with the full code of the function. To make things even more complicated, remember that the CPU stores frequently used chunks of memory in a cache on the CPU for ultra-rapid access. If you make the program's memory image big enough, your program won't be able to use the cache efficiently, and in the worst case inlining could actually slow your program down. To some extent the compiler can calculate what the trade offs are, and may be able to make better decisions than you can, just looking at the source code.

拿命拼未来 2024-07-14 09:25:22

我们的计算机科学教授敦促我们永远不要在 C++ 程序中使用内联。 当被问及原因时,他友好地向我们解释说,现代编译器应该自动检测何时使用内联。

所以,是的,内联可以是一种可以在任何可能的情况下使用的优化技术,但显然,只要有可能内联函数,这显然已经为您完成了。

Our computer science professor urged us to never use inline in a c++ program. When asked why, he kindly explained to us that modern compilers should detect when to use inline automatically.

So yes, the inline can be an optimization technique to be used wherever possible, but apparently this is something that is already done for you whenever it's possible to inline a function anyways.

坚持沉默 2024-07-14 09:25:22

来自另一个讨论的结论:

有什么缺点吗内联函数?

显然,使用内联函数没有任何问题。

但值得注意的是以下几点!

  • 过度使用内联实际上会使程序变慢。 根据函数的大小,内联它可能会导致代码大小增加或减少。 内联一个非常小的访问器函数通常会减少代码大小,而内联一个非常大的函数会显着增加代码大小。 在现代处理器上,由于更好地利用指令缓存,较小的代码通常运行得更快。 - Google 指南

  • 内联函数的速度优势随着函数规模的增大而趋于减小。 在某些时候,与函数体的执行相比,函数调用的开销变得很小,并且失去了好处- 来源

  • 在少数情况下内联函数可能不起作用:

    • 对于返回值的函数; 如果存在 return 语句。
    • 对于不返回任何值的函数; 如果存在循环、switch 或 goto 语句。
    • 如果函数是递归的。 -来源
  • __inline仅当您指定优化选项时, 关键字才会导致函数内联。 如果指定了优化,则是否遵循 __inline 取决于内联优化器选项的设置。 默认情况下,只要运行优化器,内联选项就会生效。 如果指定 optimize ,并且希望忽略 __inline 关键字,则还必须指定 noinline 选项。 -来源

Conclusion from another discussion here:

Are there any drawbacks with inline functions?

Apparently, There is nothing wrong with using inline functions.

But it is worth noting the following points!

  • Overuse of inlining can actually make programs slower. Depending on a function's size, inlining it can cause the code size to increase or decrease. Inlining a very small accessor function will usually decrease code size while inlining a very large function can dramatically increase code size. On modern processors smaller code usually runs faster due to better use of the instruction cache. - Google Guidelines

  • The speed benefits of inline functions tend to diminish as the function grows in size. At some point the overhead of the function call becomes small compared to the execution of the function body, and the benefit is lost - Source

  • There are few situations where an inline function may not work:

    • For a function returning values; if a return statement exists.
    • For a function not returning any values; if a loop, switch or goto statement exists.
    • If a function is recursive. -Source
  • The __inline keyword causes a function to be inlined only if you specify the optimize option. If optimize is specified, whether or not __inline is honored depends on the setting of the inline optimizer option. By default, the inline option is in effect whenever the optimizer is run. If you specify optimize , you must also specify the noinline option if you want the __inline keyword to be ignored. -Source

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