#C++基础# inline __forceinline __attribute__((always_inline)内联函数

inline 

inline是C++关键字,在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。这样可以解决一些频繁调用的函数大量消耗栈空间(栈内存)的问题。关键字inline必须与函数定义放在一起才能使函数成为内联函数,仅仅将inline放在函数声明前面不起任何作用。inline是一种“用于实现”的关键字,而不是一种“用于声明”的关键字。

错误全局函数例子:function_inline

inline void function_inline();
void function_inline()
{
    std::cout << __FILE__ << ":" << __LINE__ << "/" << __FUNCTION__ << std::endl;
}

正确全局函数例子:function_inline

inline void function_inline()
{
    std::cout << __FILE__ << ":" << __LINE__ << "/" << __FUNCTION__ << std::endl;
}

错误成员函数例子:class_inline::function_inline

//class_inline.h
class class_inline 
{
    public: 
    inline void function_inline();
};

//class_inline.cpp
void class_inline::function_inline()
{
    std::cout << __FILE__ << ":" << __LINE__ << "/" << __FUNCTION__ << std::endl;
}

正确成员函数例子:class_inline::function_inline

推荐!

//class_inline.h
class class_inline 
{
public: 
    inline void function_inline() 
    {
        std::cout << __FILE__ << ":" << __LINE__ << "/" << __FUNCTION__ << std::endl;
    }
};

不推荐! 

//class_inline.h
class class_inline 
{
public: 
    inline void function_inline();
};

//class_inline.cpp
inline void class_inline::function_inline()
{
    std::cout << __FILE__ << ":" << __LINE__ << "/" << __FUNCTION__ << std::endl;
}

不推荐!  

//class_inline.h
class class_inline {
public: 
    void function_inline();
};

//class_inline.cpp
inline void class_inline::function_inline()
{
    std::cout << __FILE__ << ":" << __LINE__ << "/" << __FUNCTION__ << std::endl;
}

inline函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思,它如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联,声明内联只是一个建议而已。

Also, this, for GCC/C99.

The extent to which suggestions made by using the inline function specifier are effective (C99 6.7.4).

  • GCC will not inline any functions if the -fno-inline option is used or if -O0 is used. Otherwise, GCC may still be unable to inline a function for many reasons; the -Winline option may be used to determine if a function has not been inlined and why not.

运的是大多数编译器提供了一个诊断级别:如果它们无法将你要求的函数 inline 化, 会给你一个警告信息。

 

inline限制

inline只适合函数体内简单代码的涵数使用。不能包含复杂的结构控制语句例如while、switch,并且不能内联函数本身不能是直接递归函数(即,自己内部还调用自己的函数)。而所有(除了最平凡,几乎什么也没做)的虚拟函数,都会阻止inline的进行。因为virtual意味着”等待,直到执行时期再确定应该调用哪一个函数“,而inline却意味着”在编译阶段,将调用动作以被调用函数的主体取代之“。如果编译器做决定时,尚不知道该调用哪一个函数,很难责成他们做出一个inline函数。

 

慎用inline

内联为提高函数的执行效率,以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的执行效率。 如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。因此,需要酌情使用。

以下情况不宜使用内联: 

  • (1) 如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。 
  • (2) 如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
  • (3)  类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。所以不要随便地将构造函数和析构函数的定义体放在类声明中。

一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了 inline 不应该出现在函数的声明中)。即“inline函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思”,当有编译宏明确需要使用内联时,请使用__forceinline __attribute__((always_inline)

 

__forceinline

编译器尝试内联函数,而不考虑函数的特征,在某些情况下,编译器可能会选择忽略__forceinline,而不内联函数。例如:

  •     递归函数永远不会内联到自身中。
  •     使用alloca()的函数从不内联。

当有编译宏(COMPLIE_ZMODULE_NAME)替换时,最好还是强制内联以确保debug版本(不会编译内联函数,即使加了inline关键字)与release版本(可能优化为内联函数),从而导致COMPLIE_ZMODULE_NAME的内容存在差异引起一系列问题。

__forceinline void function_inline()
{
    std::cout << __FILE__ << ":" << __LINE__ << "/" << __FUNCTION__ << "COMPLIE_ZMODULE_NAME:" << COMPLIE_ZMODULE_NAME << std::endl;
}

__attribute__((always_inline)

编译器尝试内联函数,而不考虑函数的特征,在某些情况下,编译器可能会选择忽略__attribute__((always_inline)函数属性,而不内联函数。例如:

  •     递归函数永远不会内联到自身中。
  •     使用alloca()的函数从不内联。

当有编译宏(COMPLIE_ZMODULE_NAME)替换时,最好还是强制内联以确保debug版本(不会编译内联函数,即使加了inline关键字)与release版本(可能优化为内联函数),从而导致COMPLIE_ZMODULE_NAME的内容存在差异引起一系列问题。

inline void __attribute__((always_inline)) function_inline()
{
    std::cout << __FILE__ << ":" << __LINE__ << "/" << __FUNCTION__ << "COMPLIE_ZMODULE_NAME:" << COMPLIE_ZMODULE_NAME << std::endl;
}
发布了170 篇原创文章 · 获赞 207 · 访问量 459万+

猜你喜欢

转载自blog.csdn.net/xiaoting451292510/article/details/104965726