使用内联函数有什么问题?

发布于 2024-07-04 10:03:09 字数 1195 浏览 15 评论 0原文

虽然在某些情况下使用内联函数会非常方便,但是

内联函数有什么缺点吗?

结论

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

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

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

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

  • 在少数情况下内联函数可能无法工作:

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

While it would be very convenient to use inline functions at some situations,

Are there any drawbacks with inline functions?

Conclusion:

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

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

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

发布评论

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

评论(13

那支青花 2024-07-11 10:03:10

正如其他人提到的, inline 关键字只是对编译器的提示。 事实上,大多数现代编译器会完全忽略这个提示。 编译器有自己的启发式方法来决定是否内联函数,坦率地说,不需要您的建议,非常感谢。

如果您真的非常想要内联某些内容,如果您实际上对其进行了分析并查看了反汇编以确保覆盖编译器启发式实际上有意义,那么这是可能的:

  • 在 VC++ 中,使用 __forceinline 关键字
  • 在 GCC 中,使用__attribute__((always_inline))

然而,inline 关键字确实有第二个有效的目的 - 在头文件中声明函数,而不是在类定义中声明函数。 需要 inline 关键字来告诉编译器不要生成函数的多个定义。

As others have mentioned, the inline keyword is only a hint to the compiler. In actual fact, most modern compilers will completely ignore this hint. The compiler has its own heuristics to decide whether to inline a function, and quite frankly doesn't want your advice, thank you very much.

If you really, really want to make something inline, if you've actually profiled it and looked at the disassembly to ensure that overriding the compiler heuristic actually makes sense, then it is possible:

  • In VC++, use the __forceinline keyword
  • In GCC, use __attribute__((always_inline))

The inline keyword does have a second, valid purpose however - declaring functions in header files but not inside a class definition. The inline keyword is needed to tell the compiler not to generate multiple definitions of the function.

北城挽邺 2024-07-11 10:03:10

我对此表示怀疑。 甚至编译器也会自动内联一些函数以进行优化。

I doubt it. Even the compiler automatically inlines some functions for optimization.

七禾 2024-07-11 10:03:10

我不知道我的答案是否与问题相关,但是:

对于内联虚拟方法要非常小心! 一些有缺陷的编译器(例如 Visual C++ 的早期版本)会为虚拟方法生成内联代码,其中标准行为是不执行任何操作,而是沿着继承树向下调用适当的方法。

I don't know if my answer's related to the question but:

Be very careful about inline virtual methods! Some buggy compilers (previous versions of Visual C++ for example) would generate inline code for virtual methods where the standard behaviour was to do nothing but go down the inheritance tree and call the appropriate method.

Hello爱情风 2024-07-11 10:03:10

您还应该注意,inline 关键字只是一个请求。 编译器可能会选择不内联它,同样,如果编译器认为速度/大小权衡值得,则编译器可能会选择将您未定义为内联的函数内联。

这个决定通常是基于很多因素做出的,例如速度优化(避免函数调用)和大小优化(内联可能导致代码膨胀,因此对于大型重复使用的函数来说不太好)之间的设置。

使用 VC++ 编译器,您可以使用 __forceinline 来推翻这个决定,

一般来说:
如果您确实想在标头中包含一个函数,请使用内联,但在其他地方没有什么意义,因为如果您想从中获得任何东西,一个好的编译器无论如何都会为您使其内联。

You should also note that the inline keyword is only a request. The compiler may choose not to inline it, likewise the compiler may choose to make a function inline that you did not define as inline if it thinks the speed/size tradeoff is worth it.

This decision is generaly made based on a number of things, such as the setting between optimise for speed(avoids the function call) and optimise for size (inlining can cause code bloat, so isn't great for large repeatedly used functions).

with the VC++ compiler you can overide this decision by using __forceinline

SO in general:
Use inline if you really want to have a function in a header, but elsewhere theres little point because if your going to gain anything from it, a good compiler will be making it inline for you anyway.

饮惑 2024-07-11 10:03:10

内联较大的函数可以使程序变得更大,从而产生更多的指令缓存 错过并使其变慢。

决定函数何时足够小以进行内联会提高性能是相当棘手的。 Google 的 C++ 风格指南建议仅使用 10 行或较少的。

(简化)示例

想象一个简单的程序,仅调用函数“X”5 次。

如果 X 很小并且所有调用都是内联的:可能所有指令都将通过一次主内存访问预取到指令缓存中 - 太棒了!

如果 X 很大,假设接近指令缓存的容量:
内联 X 可能会导致为 X 的每个内联实例从内存中获取一次指令。
如果 X 未内联,则可能会在第一次调用 X 时从内存中获取指令,但可能会保留在缓存中以供后续调用。

Inlining larger functions can make the program larger, resulting in more instruction cache misses and making it slower.

Deciding when a function is small enough that inlining will increase performance is quite tricky. Google's C++ Style Guide recommends only inlining functions of 10 lines or less.

(Simplified) Example:

Imagine a simple program that just calls function "X" 5 times.

If X is small and all calls are inlined: Potentially all instructions will be prefetched into the instruction cache with a single main memory access - great!

If X is large, let's say approaching the capacity of the instruction cache:
Inlining X will potentially result in fetching instructions from memory once for each inline instance of X.
If X isn't inlined, instructions may be fetched from memory on the first call to X, but could potentially remain in the cache for subsequent calls.

冷默言语 2024-07-11 10:03:10

函数的过多内联会增加编译后的可执行文件的大小,这可能会对缓存性能产生负面影响,但现在编译器自行决定函数内联(取决于许多标准)并忽略 inline 关键字。

Excessive inlining of functions can increase size of compiled executable which can have negative impact on cache performance, but nowadays compiler decide about function inlining on their own (depending on many criterias) and ignore inline keyword.

反话 2024-07-11 10:03:10

在内联函数的其他问题中,我发现这些问题被严重过度使用(我见过 500 行的内联函数),您必须注意的是:

  • 构建不稳定

    • 更改内联函数的源会导致标头的所有用户重新编译
    • #include 泄漏到客户端。 如果您重新设计内联函数并删除某些客户端依赖的不再使用的标头,这可能会非常令人讨厌。
  • 可执行文件大小

    • 每次内联内联而不是调用指令时,编译器都必须生成内联的完整代码。 如果函数的代码很短(一两行),这还可以,但如果函数很长,则不太好
    • 某些函数可能会生成比最初出现的代码多得多的代码。 我的例子是一个类的“简单”析构函数,该类具有许多非 pod 成员变量(或两个或 3 个具有相当混乱的析构函数的成员变量)。 必须为每个析构函数生成一个调用。
  • 执行时间

    • 这很大程度上取决于您的 CPU 缓存和共享库,但引用的位置很重要。 如果您可能内联的代码恰好保存在 CPU 缓存中的一个位置,则许多客户端可以找到该代码,而不会遭受缓存未命中和随后的内存获取(更糟糕的是,如果发生这种情况,则会发生磁盘获取) 。 遗憾的是,这是您真正需要进行性能分析的情况之一。

我工作的编码标准将内联函数限制为简单的 setter/getter,并特别指出析构函数不应该是内联的,除非您有性能测量来显示内联带来了明显的优势。

Among other issues with inline functions, which I've seen heavily overused (I've seen inline functions of 500 lines), what you have to be aware of are:

  • build instability

    • Changing the source of an inline function causes all the users of the header to recompile
    • #includes leak into the client. This can be very nasty if you rework an inlined function and remove a no-longer used header which some client has relied on.
  • executable size

    • Every time an inline is inlined instead of a call instruction the compiler has to generate the whole code of the inline. This is OK if the code of the function is short (one or two lines), not so good if the function is long
    • Some functions can produce a lot more code than at first appears. I case in point is a 'trivial' destructor of a class that has a lot of non-pod member variables (or two or 3 member variables with rather messy destructors). A call has to be generated for each destructor.
  • execution time

    • this is very dependent on your CPU cache and shared libraries, but locality of reference is important. If the code you might be inlining happens to be held in cpu cache in one place, a number of clients can find the code an not suffer from a cache miss and the subsequent memory fetch (and worse, should it happen, a disk fetch). Sadly this is one of those cases where you really need to do performance analysis.

The coding standard where I work limit inline functions to simple setters/getters, and specifically say destructors should not be inline, unless you have performance measurements to show the inlining confers a noticeable advantage.

稚气少女 2024-07-11 10:03:10

除了其他很好的答案之外,至少有一次我看到强制内联实际上使受影响的代码减慢了 1.5 倍的情况。 里面有一个嵌套循环(相当小的一个),当这个函数被编译为一个单独的单元时,编译器设法有效地展开和优化它。 但是,当相同的函数被内联到更大的外部函数中时,编译器(MSVC 2017)无法优化此循环。

In addition to other great answers, at least once I saw a case where forced inlining actually slowed down the affected code by 1.5x. There was a nested loop inside (pretty small one) and when this function was compiled as a separate unit, compiler managed to efficiently unroll and optimize it. But when same function was inlined into much bigger outer function, compiler (MSVC 2017) failed to optimize this loop.

此刻的回忆 2024-07-11 10:03:10
  1. 正如其他人所说,如果代码很大,内联函数会产生问题。由于每条指令都存储在特定的内存位置,因此内联函数的重载会使代码需要更多时间才能执行。

  2. 在其他情况下,内联可能不起作用

    1. 在递归函数的情况下不起作用。
    2. 它也可能不适用于静态变量。
    3. 如果使用循环、开关等,或者我们可以用多个语句来表示,它也不起作用。
    4. 并且 main 函数不能作为内联函数使用。
  1. As other people said that inline function can create a problem if the the code is large.As each instruction is stored in a specific memory location ,so overloading of inline function make a code to take more time to get exicuted.

  2. there are few other situations where inline may not work

    1. does not work in case of recursive function.
    2. It may also not work with static variable.
    3. it also not work in case there is use of a loop,switch etc.or we can say that with multiple statements.
    4. And the function main cannot work as inline function.
愁以何悠 2024-07-11 10:03:10

值得指出的是,inline关键字实际上只是对编译器的一个提示。 编译器可能会忽略内联并简单地在某处生成该函数的代码。

内联函数的主要缺点是它会增加可执行文件的大小(取决于实例化的数量)。 在某些平台(例如嵌入式系统)上这可能是一个问题,特别是如果函数本身是递归的。

我还建议使内联函数非常小 - 内联函数的速度优势往往会随着函数大小的增大而减弱。 在某些时候,与函数体的执行相比,函数调用的开销变得很小,并且失去了好处。

It worth pointing out that the inline keyword is actually just a hint to the compiler. The compiler may ignore the inline and simply generate code for the function someplace.

The main drawback to inline functions is that it can increase the size of your executable (depending on the number of instantiations). This can be a problem on some platforms (eg. embedded systems), especially if the function itself is recursive.

I'd also recommend making inline'd functions very small - 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.

深海夜未眠 2024-07-11 10:03:10

它可以增加尺寸
可执行,而且我不认为
编译器实际上总是会做出
即使您使用了它们内联
内联关键字。 (或者是另一个
周围,​​就像Vaibhav
说?...)

我认为如果
函数只有 1 或 2 条语句。

编辑:这是 linux CodingStyle 文档对此的说明:

第 15 章:内联疾病

似乎有一个共同点
误解 gcc 有魔法
“让我更快”加速选项称为
“排队”。 虽然使用内联可以
适当(例如作为一种手段
替换宏,参见第 12 章),
但通常情况并非如此。 大量使用
inline 关键字会导致很多
更大的内核,这反过来又减慢了
系统整体瘫痪,由于
CPU 的 icache 占用空间更大
仅仅因为数量较少
可用于页面缓存的内存。
考虑一下; 页面缓存未命中
导致磁盘寻道,这很容易花费
5 毫秒。 有很多cpu
可以进入这 5 个周期
毫秒。

合理的经验法则是不要
将内联放在具有更多内容的函数中
其中超过 3 行代码。 一个
此规则的例外情况是
其中参数已知为
编译时常量,结果
知道这种恒定性
编译器将能够优化大多数
你的函数在编译时就消失了。
对于后面这个案例的一个很好的例子,
请参阅 kmalloc() 内联函数。

人们经常争论添加内联
静态和已使用的函数
只有一次总是胜利,因为有
没有空间权衡。 虽然这是
技术上正确,gcc 能够
自动内联这些,无需
帮助和维护问题
当第二个用户时删除内联
看起来大于潜在价值
告诉 gcc 做什么的提示
无论如何它都会做的事情。

It could increase the size of the
executable, and I don't think
compilers will always actually make
them inline even though you used the
inline keyword. (Or is it the other
way around, like what Vaibhav
said?...)

I think it's usually OK if the
function has only 1 or 2 statements.

Edit: Here's what the linux CodingStyle document says about it:

Chapter 15: The inline disease

There appears to be a common
misperception that gcc has a magic
"make me faster" speedup option called
"inline". While the use of inlines can
be appropriate (for example as a means
of replacing macros, see Chapter 12),
it very often is not. Abundant use of
the inline keyword leads to a much
bigger kernel, which in turn slows the
system as a whole down, due to a
bigger icache footprint for the CPU
and simply because there is less
memory available for the pagecache.
Just think about it; a pagecache miss
causes a disk seek, which easily takes
5 miliseconds. There are a LOT of cpu
cycles that can go into these 5
miliseconds.

A reasonable rule of thumb is to not
put inline at functions that have more
than 3 lines of code in them. An
exception to this rule are the cases
where a parameter is known to be a
compiletime constant, and as a result
of this constantness you know the
compiler will be able to optimize most
of your function away at compile time.
For a good example of this later case,
see the kmalloc() inline function.

Often people argue that adding inline
to functions that are static and used
only once is always a win since there
is no space tradeoff. While this is
technically correct, gcc is capable of
inlining these automatically without
help, and the maintenance issue of
removing the inline when a second user
appears outweighs the potential value
of the hint that tells gcc to do
something it would have done anyway.

你与清晨阳光 2024-07-11 10:03:10

内联存在一个问题 - 一旦您在头文件中定义了一个函数(这意味着通过在类内部定义成员函数的主体来显式或隐式地内联),就没有简单的方法可以在不强制用户重新编译的情况下更改它(与重新链接相对)。 这通常会导致问题,特别是当相关函数是在库中定义并且头文件是其接口的一部分时。

There is a problem with inline - once you defined a function in a header file (which implies inline, either explicit or implicit by defining a body of a member function inside class) there is no simple way to change it without forcing your users to recompile (as opposed to relink). Often this causes problems, especially if the function in question is defined in a library and header is part of its interface.

琴流音 2024-07-11 10:03:10

我同意其他帖子:

  • 内联可能是多余的,因为编译器会
  • 内联执行它可能会使您的代码膨胀

第三点是它可能会迫使您在标头中公开实现细节,例如,

class OtherObject;

class Object {
public:
    void someFunc(OtherObject& otherObj) {
        otherObj.doIt(); // Yikes requires OtherObj declaration!
    }
};

如果没有内联,则 OtherObject 的前向声明是所有你需要的。 随着内联你的
header 需要OtherObject 的定义。

I agree with the other posts:

  • inline may be superfluous because the compiler will do it
  • inline may bloat your code

A third point is it may force you to expose implementation details in your headers, .e.g.,

class OtherObject;

class Object {
public:
    void someFunc(OtherObject& otherObj) {
        otherObj.doIt(); // Yikes requires OtherObj declaration!
    }
};

Without the inline a forward declaration of OtherObject was all you needed. With the inline your
header needs the definition for OtherObject.

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