我可以选择性地(强制)内联函数吗
Can I selectively (force) inline a function?
在《清洁代码》一书(以及我读过的其他几本书(中,建议保持函数较小,如果函数变大,则将其分解。它还建议函数应该只做一件事。
在C++中的优化软件中,Agner Fog表示,他不喜欢仅仅因为函数超过了一定的阈值(即多行(就分解函数的规则。他表示,这会导致不必要的跳跃,从而降低性能。
首先,我明白,如果我正在处理的代码没有处于一个紧密的循环中,并且函数很重,那么调用它们所需的时间与函数中代码执行所用的时间相比是微不足道的。但是,让我们假设我使用的函数在大多数情况下被其他对象/函数使用,并且执行相对琐碎的任务。这些功能遵循第一段中列出的建议(即,执行一个单一的功能,并且很小/易于理解(。然后我开始编程一个性能关键函数,它在一个紧密的循环中利用这些其他函数,本质上是一个框架函数。最后,假设排列它们对性能关键函数有好处,但对任何其他函数都没有好处(是的,我已经对此进行了介绍,尽管我想避免大量的复制和粘贴(。
立即,可以说标记函数inline
并让编译器选择。但是,如果我不希望所有这些函数都在`.inl文件中或在标头中公开,该怎么办?在我目前的情况下,性能关键函数和它使用的其他函数都在同一个源文件中。
总之,我是否可以选择性地(强制(为单个函数内联一个函数,以便最终代码表现得像一个大函数,而不是对其他函数的多次调用。
没有什么可以阻止您将内联放入.cpp文件中的静态函数中。
一些编译器可以选择强制内联函数,例如参见GCC属性((always_inline((,以及大量用于微调内联优化的选项(参见-minline-*参数(。
我的建议是在任何您认为合适的地方使用内联或更好的静态内联
您不能强制内联。此外,与所做工作的成本相比,函数调用在现代CPU上相当便宜。如果您的函数足够大,需要进行分解,那么执行调用所需的额外时间将基本上为零。
如果做不到,你可能。。。尝试使用宏。
否,inline
是编译器的推荐;它不会强迫它做任何事情。此外,如果您使用的是MSVC++,请注意__forceinline
也是一个用词不当的词;它只是一个比inline
更强的推荐。
这既是关于C++的,也是关于好的老式直C的。前几天我在思考这个问题,因为在一个需要仔细管理速度和空间的嵌入式世界里,这真的很重要(而不是经常说的"别担心,你的编译器很智能,内存在桌面/服务器开发中很便宜"(
我还没有审查的一个可能的解决方案是基本上为不同的变体使用两个名称,比如
inline int _max(int a, int b) {
return a > b ? a : b;
}
然后
int max(int a, int b) {
return _max(a, b);
}
这将使一个人能够选择性地调用_max((或max((,同时仍然只定义一次算法。
内联-例如,如果存在一个经常调用函数B的函数a,而函数B相对较小,则配置文件导向优化将在函数a中内联函数B。
VS档案引导优化
您可以使用性能和诊断中心中的Visual C++自动配置文件优化插件来简化和优化Visual Studio中的优化过程,也可以在Visual Studio中或命令行上手动执行优化步骤我们推荐使用该插件,因为它更易于使用有关如何获取插件并使用它优化应用程序的信息,请参阅配置文件导向优化插件。
如果您有一个已知的热函数,并且希望编译器比通常更积极地内联,那么gcc/clang提供的flatten属性可能是值得研究的。与内联关键字和属性相反,它适用于与标记函数中调用的函数相关的内联决策。
__attribute__((flatten)) void hot_code() {
// functions called here will be inlined if possible
}
请参阅https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html和https://clang.llvm.org/docs/AttributeReference.html#flatten官方文件。
编译器实际上非常擅长生成优化的代码。
我建议将代码组织成逻辑分组(如果可以增强可读性,则使用额外的函数(,在适当的情况下将它们标记为内联,并让编译器决定最佳生成什么代码。
非常惊讶,这还没有被提及,但到目前为止,你可以告诉编译器(我相信它可能只适用于GCC/G++(强制内联一个函数,并忽略与之相关的几个限制。
您可以通过__attribute__((always_inline))
执行此操作。
使用中的示例:
inline __attribute__((always_inline)) int pleaseInlineThis() {
return 5;
}
通常情况下,你应该避免强制内联,因为编译器比你更清楚什么是最好的;然而,有一些用例,例如在OS/MicroController开发中,您需要内联调用,如果调用它,就会破坏功能。
C++编译器通常对受控环境不太友好,比如那些没有一些技巧的环境。
正如人们所提到的,您应该避免这样做,因为编译器通常会做出更好的决定。您可以启用几种优化来提高性能。如果需要,这些功能将内联:
- LTO:链接时间优化或过程间优化
- 配置文件导向优化:基于运行时配置文件的优化
- BOLT:二进制优化和布局工具
- Polly:一个高级循环和数据局部优化器
- 如何修复函数样式强制转换或类型构造的预期"("?
- 函数作为模板参数,是否对返回类型强制约束
- enable_if转换构造函数(静态强制转换,is_base_of)
- 将字符缓冲区强制转换为函数指针
- 强制使用默认构造函数对成员进行未初始化的声明
- 当我使用 void 函数的返回值(通过强制转换函数指针)时,究竟会发生什么?
- 调用不在基类中的派生类函数而不进行动态强制转换,以最大程度地提高性能
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- 如何在构造函数中传递 const 引用时强制编译器不接受右值
- 了解类构造函数的静态强制转换
- C++根据调用的构造函数强制编译时错误
- 将函数强制转换为成员函数
- 在类自己的成员函数中构造类时,如何强制类模板参数推导?
- 函数返回动态强制转换的指针,返回指针,就好像它根本没有被转换一样
- 从类型"void*"到函数指针的强制转换无效
- 对外部函数的调用是否强制从内存加载
- 将子类的成员函数强制转换为父类
- 如何通过内联函数强制常量传播
- 将基类构造函数强制转换为派生类构造函数是什么意思?
- 函数强制转换中作为复合表达式处理的表达式列表[-fpermissive]