#1 楼
内联函数速度更快,因为您不需要像往常一样将参数和返回地址压入/弹出堆栈。但是,它的确会使二进制文件稍大。它有很大的不同吗?对于大多数人来说,在现代硬件上还不够明显。但这可以有所作为,对某些人来说就足够了。
将内容标记为内联并不能保证将其内联。这只是对编译器的建议。有时,例如当您具有虚函数或涉及递归时,这是不可能的。有时,编译器只是选择不使用它。
我可以看到这样的情况产生了明显的变化:
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);
评论
我怀疑内联对上面没有影响。与gcc 4.01一起编译。版本1强制使用内联:48.318u 1.042s 5:51.39 99.4%0 + 0k 0 + 0io 0pf + 0w版本2强制没有内联348.311u 1.019s 5:52.31 99.1%0 + 0k 0 + 0io 0pf + 0w这是一个很好的例子是常识是错误的。
–马丁·约克
08-09-28在20:38
虽然通话本身确实很重要,但这仅是使用内联获得的次要收益。主要的好处是,编译器现在可以看到指针彼此之间不互为别名,调用方的变量最终位于被调用方中,依此类推。因此,以下优化更为重要。
– Johannes Schaub-小人
08年10月10日在8:04
由于该函数的结果从未使用过,因此该函数也没有副作用,因此在此代码段中可能没有什么不同。我们在图像处理的内联中看到了可观的性能提升。
–底座
10 Mar 2 '10 at 14:28
没有差异的原因可能是编译器可以自行内联;或代码很小,因此没有代码预取问题。
– einpoklum
15年12月19日在16:15
因此,编译器甚至可能优化了整个循环。
–noɥʇʎԀʎzɐɹƆ
16年6月13日在16:51
#2 楼
优点通过在需要的地方插入代码,您的程序将在函数调用和返回部分上花费更少的时间。它应该使您的代码运行得更快,即使它变得更大(请参见下文)。内联琐碎的访问器可能是有效内联的一个示例。
通过将其标记为内联,可以将函数定义放在头文件中(即可以将其包含在多个编译单元中,而无需链接程序抱怨)
缺点
它可以使您的代码更大(即,如果对非平凡函数使用内联)。这样,它可能会引起编译器的分页并破坏优化。
它会稍微破坏您的封装,因为它公开了对象处理的内部(但是,每个“私有”成员也会)。这意味着您不能在PImpl模式中使用内联。
它会稍微破坏您的封装2:C ++内联在编译时已解决。这意味着应该更改内联函数的代码,需要使用它重新编译所有代码,以确保将其更新(出于相同的原因,我避免使用函数参数的默认值)
使用时在标头中,它会使您的标头文件变大,从而将用用户不关心的代码来稀释有趣的信息(例如类方法的列表)(这就是我在类内声明内联函数的原因,但会在类主体之后的标头中定义它,而永远不要在类主体中定义它。)
内联Magic
编译器可能会或可能不会内联您标记为的函数排队;它也可能决定在编译或链接时将未标记为内联的内联函数。
内联的工作方式类似于由编译器控制的复制/粘贴,这与预处理器宏有很大不同:宏将被强制内联,将污染所有名称空间和代码,不容易调试,甚至可以完成
在类本身内定义的类的每个方法都被视为“内联”(即使编译器仍可以决定不对其进行内联
Virtual方法不应被认为是不可移植的,但是有时,当编译器可以肯定地知道对象的类型时(即,该对象是在同一函数体内声明并构造的),即使是虚函数也将被内联,因为编译器知道
模板方法/函数并不总是内联的(它们在标头中并不会使它们自动内联)。
“ inline”之后的下一步是模板元编程。有时在编译时“内联”代码S,编译器可以推断出函数的最终结果...因此,有时可以将复杂的算法简化为一种
return 42 ;
语句。对我来说,这是极端的内联。它在现实生活中很少发生,它使编译时间更长,不会膨胀您的代码,并使您的代码更快。但是像圣杯一样,不要尝试将其应用到任何地方,因为大多数处理都无法通过这种方式解决...尽管如此,这仍然很酷... :-p 评论
您说过,这会稍微破坏您的封装。您能用一个例子解释一下吗?
–析构函数
2015年9月6日下午13:59
@PravasiMeet:它是C ++。假设您将DLL /共享库交付给客户端,然后针对该客户端进行编译。使用成员变量X并执行Y的内联函数foo将内联到客户端代码中。假设需要交付DLL的更新版本,将成员变量更改为Z,并在工作Y之外添加工作YY。客户端仅将DLL复制到其项目和BOOM中,因为foo的代码二进制文件中的内容不是您编写的更新代码...尽管客户端没有合法访问您的私人代码的权限,但是内联使其变得“公开”。
–paercebal
2015年9月7日在8:38
@paercebal关于倒数第二个要点,您能举一个当函数模板不是内联时的例子吗?我以为他们总是在线的,尽管我现在没有参考资料(不过,通过简单的测试似乎可以确认这一点)。
–康拉德·鲁道夫(Konrad Rudolph)
16年6月22日在9:37
@KonradRudolph在n4594中,我看到:3.2 / 6:可以使用外部链接[..]非静态功能模板对[..]内联函数进行多个定义。在5.1.5 / 6中,对于通用lambda,闭包类型具有公共内联函数调用运算符成员模板。在7.1.2 / 2中:inline关键字的使用是声明一个内联函数,建议在调用点内联该函数体。因此,我得出结论,即使内联函数和函数模板的行为相同,它们仍然是可以混合的正交概念(即内联函数模板)
–paercebal
16年7月10日在10:08
封装坏了吗?为何如此?封装是针对小伙子编程的,而不是针对内存中的实际对象的。那时没有人在乎。即使您分发了一个库,编译器也可能自行选择内联还是不进行内联。因此,最后获得新库时,只需重新编译使用该库中的函数和对象的所有内容。
–FalcoGer
19-4-2在6:36
#3 楼
在古老的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
,则链接器将发出投诉。#4 楼
内联是对编译器的建议,可以随意忽略。如果您的函数是内联的,则基本上是插入到对其进行函数调用的代码中,而不是实际调用单独的函数。这可以帮助提高速度,因为您不必执行实际的调用。
它还可以帮助CPU进行流水线操作,因为它们不必使用调用引起的新指令重新加载流水线。 br />
唯一的缺点是可能会增加二进制大小,但是,只要函数很小,就不会太大。
我倾向于将这些决策留给如今的编译器(无论如何,还是聪明的)。编写它们的人往往对底层体系结构有更详细的了解。
#5 楼
内联函数是编译器使用的优化技术。只需在函数原型前添加inline关键字即可使函数内联。内联函数指示编译器在代码中使用该函数的位置插入该函数的完整主体。它不需要函数调用开销。
还节省了函数调用时堆栈上的变量push / pop的开销。
还节省了从函数返回调用的开销。
通过利用指令缓存增加了引用的局部性。
如果指定的话,在内联编译器之后也可以应用过程内优化。这是最重要的一项,通过这种方式,编译器现在可以专注于死代码的消除,可以更加注重分支预测,归纳变量的消除等。
要对此进行更多检查,请遵循以下步骤链接
http://tajendrasengar.blogspot.com/2010/03/what-is-inline-function-in-cc.html
评论
1)这是一个建议,而不是一条指令2)如果经常内联很多常用函数,则可能由于代码大小的增加而导致更多的高速缓存未命中
– Flexo♦
2011年9月14日在18:09
末尾的链接是您的个人博客吗?如果是这样,则应这样声明,否则看起来像垃圾邮件。
– Flexo♦
2011年9月14日18:10
#6 楼
我想补充一点,在构建共享库时,内联函数至关重要。如果没有内联标记函数,它将以二进制形式导出到库中。如果已导出,它还将出现在符号表中。另一方面,内联函数不会导出到库二进制文件或符号表中。打算在运行时加载库时,这可能很关键。它还可能会访问二进制兼容感知库。在这种情况下,请勿使用内联。
评论
@Johnsyweb:请仔细阅读我的答案。当您构建可执行文件时,您所说的是正确的。但是编译器在构建共享库时不能简单地忽略内联!
–doc
2010年5月20日6:50
#7 楼
在优化期间,即使您未标记函数,许多编译器也会内联函数。如果您不知道编译器有什么知识,通常只需要将函数标记为内联即可,因为它通常可以自行做出正确的决定。评论
许多编译器也不会这样做,例如MSVC不会这样做,除非您告诉它
– paulm
2014年1月2日在15:23
#8 楼
inline
允许您将函数定义放置在头文件中,#include
将该头文件放置在多个源文件中,而不会违反一个定义规则。评论
出于记录目的,内联的静态和静态谓词也是如此,并且更直接地定义为“在此翻译单元之外不可见”。
–mtraceur
9月25日20:40
#9 楼
一般来说,如今,任何现代编译器都担心内联任何东西,这几乎是在浪费时间。实际上,编译器应该通过自己对代码的分析以及传递给编译器的优化标志的规范来为您优化所有这些注意事项。如果您关心速度,请告诉编译器优化速度。如果您关心空间,请告诉编译器优化空间。另一个提到的答案是,如果一个体面的编译器确实有意义,它甚至会自动内联。也正如其他人所说的那样,使用内联并不能保证任何内联。如果要保证,则必须定义一个宏而不是一个内联函数。
何时内联和/或定义一个宏以强制包含? -仅当已知的关键代码段的速度得到了证明的和必要的证明的提高时,已知该代码的关键部分会影响应用程序的整体性能。
评论
…如果关心空间,请告诉编译器优化空间-告诉编译器优化速度可能会导致使用C ++和C的二进制文件较小。类似地,告诉编译器优化空间会导致更快的执行速度。现在,这些功能并不总是像广告中那样起作用。与编译器的广义解释(必须保持快速可用)相比,人类具有更好地理解其程序某些方面的能力。人为干预不一定是一件坏事。
–贾斯汀
13年7月15日在21:58
#10 楼
这并不关乎性能。位于硬件之上的C ++和C都用于嵌入式编程。例如,如果要编写一个中断处理程序,则需要确保可以立即执行该代码,而无需交换其他寄存器和/或内存页。那就是内联派上用场的时候。优秀的编译器在需要速度时会自行执行一些“内联”,但是会“强制内联”。#11 楼
将函数内联到so库中会遇到同样的麻烦。内联函数似乎没有编译到库中。因此,如果可执行文件要使用库的内联函数,则链接器会发出“未定义引用”错误。 (发生在我使用gcc 4.5编译Qt源代码时。#12 楼
为什么不默认使所有函数内联?因为这是工程上的折衷。至少有两种类型的“优化”:加速程序并减小程序的大小(内存占用)。内联通常会加快处理速度。它消除了函数调用的开销,避免了从堆栈中压入然后拉出参数。但是,这也使程序的内存占用量更大,因为现在必须用函数的完整代码替换每个函数调用。要使事情变得更加复杂,请记住,CPU将频繁使用的内存块存储在CPU的高速缓存中,以进行超快速访问。如果您使程序的内存映像足够大,则您的程序将无法有效地使用高速缓存,并且在最坏的情况下,内联实际上会降低程序的速度。只需查看源代码,编译器就可以在某种程度上计算出什么是折衷方案,并且可能比您可以做出更好的决策。#13 楼
我们的计算机科学教授敦促我们不要在c ++程序中使用内联。当被问到为什么时,他友好地向我们解释了现代编译器应该检测何时自动使用内联。是的,内联可以是一种尽可能使用的优化技术,但是显然这是一种只要有可能内联函数,就已经为您完成了。
评论
不幸的是,你的教授是完全错误的。 C ++中的inline有两个非常不同的含义-只有其中一个与优化有关,而您的教授在这方面是正确的。但是,内联的第二个含义通常是满足“一个定义”规则所必需的。
–康拉德·鲁道夫(Konrad Rudolph)
16 Jun 22'9:39
#14 楼
此处的另一个讨论得出的结论是:内联函数有什么缺点吗?
显然,使用内联函数没有什么问题。
但是值得注意以下几点!
内联的过度使用实际上会使程序变慢。根据函数的大小,对其内联会导致代码大小增加或减少。内联非常小的访问器函数通常会减小代码大小,而内联非常大的函数则可以大大增加代码大小。在现代处理器上,由于更好地使用了指令缓存,因此较小的代码通常可以更快地运行。 -Google指南
随着函数尺寸的增加,内联函数的速度优势趋于减少。在某些时候,与函数主体的执行相比,函数调用的开销变小,并且失去了好处-源
在某些情况下,内联函数可能不起作用:
对于返回值的函数;如果存在return语句。
对于不返回任何值的函数;如果存在循环,开关或转到语句。
如果函数是递归的。 -Source
仅当您指定optimize选项时,
__inline
关键字才会使函数内联。如果指定了optimize,则是否接受__inline
取决于内联优化器选项的设置。默认情况下,只要运行优化器,内联选项就会生效。如果指定optimize,则如果要忽略__inline
关键字,还必须指定noinline选项。 -来源评论
如果内联是命令而不是对编译器的提示,则为true。编译器实际上决定要内联的内容。
–马丁·约克
08年9月28日在21:09
@LokiAstari我知道内联是对编译器的请求。我的观点是,如果它对编译器有提示,我们应该将其留给编译器来决定最佳选择。为什么以内联方式使用内联,即使您使用内联,仍然由编译器做出最终决定。我也想知道我的微软是否已引入_forceinline。
–克里希纳·奥扎(Krishna Oza)
2014年2月12日下午6:44
@krish_oza:我的评论在这里。关于这个答案。答案是完全错误的。因为编译器会忽略用于确定是否内联代码的inline关键字,所以上述所有要点都是错误的。如果编译器使用关键字进行内联(它们仅用于确定标记多个定义以进行链接),则它们将为true。
–马丁·约克
2014年2月12日在21:20
评论
这是常识错误的问题之一。每个人都回答了标准的Comp Sci答案。 (内联节省了函数调用成本,但增加了代码大小)。垃圾。它为编译器提供了一种应用更多优化的简单机制。这是伪装成评论的答案之一。如果您不喜欢已发布的任何答案,请发布您自己的答案并查看其结果。
这个问题的基础是有缺陷的。 C ++内联函数与编译期间内联的编译器无关。不幸的是,内联是c ++关键字,内联是编译器优化技术。请参见此问题“何时应该为功能/方法编写关键字内联”以获取正确答案。
@JoseVega您的链接被弄乱了-当前链接是exforsys.com/tutorials/c-plus-plus/inline-functions.html