inline_inline 函数 - CSDN
inline 订阅
inline是C++关键字,在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。这样可以解决一些频繁调用的函数大量消耗栈空间(栈内存)的问题。关键字inline必须与函数定义放在一起才能使函数成为内联函数,仅仅将inline放在函数声明前面不起任何作用。inline是一种“用于实现”的关键字,而不是一种“用于声明”的关键字。 [1] 展开全文
inline是C++关键字,在函数声明或定义中,函数返回类型前加上关键字inline,即可以把函数指定为内联函数。这样可以解决一些频繁调用的函数大量消耗栈空间(栈内存)的问题。关键字inline必须与函数定义放在一起才能使函数成为内联函数,仅仅将inline放在函数声明前面不起任何作用。inline是一种“用于实现”的关键字,而不是一种“用于声明”的关键字。 [1]
信息
外文名
inline
特    点
C++关键字
中文名
内联函数(宏定义)
功    能
define ExpressionName
inlineC++中定义格式
一、inline关键字用来定义一个类的内联函数,引入它的主要原因是用它替代C中表达式形式的宏定义。表达式形式的宏定义如:#define ExpressionName(Var1,Var2) ((Var1)+(Var2))*((Var1)-(Var2))取代这种形式的原因如下:1.C中使用define这种形式宏定义的原因是因为,C语言是一个效率很高的语言,这种宏定义在形式及使用上像一个函数,但它使用预处理器实现,没有了参数压栈,代码生成等一系列的操作。因此,效率很高,这是它在C中被使用的一个主要原因。2.这种宏定义在形式上类似于一个函数,但在使用它时,仅仅只是做预处理器符号表中的简单替换,因此它不能进行参数有效性的检测,也就不能享受C++编译器严格类型检查的好处,另外它的返回值也不能被强制转换为可转换的合适的类型。这样,它的使用就存在着一系列的隐患和局限性。3.在C++中引入了类及类的访问控制,这样,如果一个操作或者说一个表达式涉及到类的保护成员或私有成员,你就不可能使用这种宏定义来实现(因为无法将this指针放在合适的位置)。4.inline推出的目的,也正是为了取代这种表达式形式的宏定义,它消除了宏定义的缺点,同时又很好地继承了宏定义的优点。对应于上面的1-3点,阐述如下:1.inline定义的类的内联函数,函数的代码被放入符号表中,在使用时直接进行替换(像宏一样展开),没有了调用的开销,效率也很高。2.很明显,类的内联函数也是一个真正的函数,编译器在调用一个内联函数时,会首先检查它的参数的类型,保证调用正确。然后进行一系列的相关检查,就像对待任何一个真正的函数一样。这样就消除了它的隐患和局限性。3.inline可以作为某个类的成员函数,当然就可以在其中使用所在类的保护成员及私有成员。在何时使用inline函数:首先,你可以使用inline函数完全取代表达式形式的宏定义。另外要注意,内联函数一般只会用在函数内容非常简单的时候。这是因为,内联函数的代码会在任何调用它的地方展开,如果函数太复杂,代码膨胀带来的恶果很可能会大于效率的提高带来的益处。内联函数最重要的使用地方是用于类的存取函数。 [2] 
收起全文
精华内容
参与话题
  • inline用法详解

    千次阅读 2017-06-21 15:29:22
    (一)inline函数(摘自C++ Primer的第三版)  在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联。  inline int min(int first, int secend) {/****/};  inline函数对编译器而言...

    (一)inline函数(摘自C++ Primer的第三版)

          在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联。

          inline int min(int first, int secend) {/****/};

            inline函数对编译器而言必须是可见的,以便它能够在调用点内展开该函数。与非inline函数不同的是,inline函数必须在调用该函数的每个文本文件中定义。当然,对于同一程序的不同文件,如果inline函数出现的话,其定义必须相同。对于由两个文件compute.C和draw.C构成的程序来说,程序员不能定义这样的min()函数,它在compute.C中指一件事情,而在draw.C中指另外一件事情。如果两个定义不相同,程序将会有未定义的行为.

            为保证不会发生这样的事情,建议把inline函数的定义放到头文件中。在每个调用该inline函数的文件中包含该头文件。这种方法保证对每个inline函数只有一个定义,且程序员无需复制代码,并且不可能在程序的生命期中引起无意的不匹配的事情。

    (二)内联函数的编程风格(摘自高质量C++/C 编程指南)

    关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用

    如下风格的函数Foo 不能成为内联函数:
    inline void Foo(int x, int y); // inline 仅与函数声明放在一起
    void Foo(int x, int y)
    {
    }
    而如下风格的函数Foo 则成为内联函数:
    void Foo(int x, int y);
    inline void Foo(int x, int y) // inline 与函数定义体放在一起
    {
    }
    所以说,inline 是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但我认为inline 不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。


    定义在类声明之中的成员函数将自动地成为内联函数,例如
    class A
    {
    public:
    void Foo(int x, int y) {  } // 自动地成为内联函数
    }
    将成员函数的定义体放在类声明之中虽然能带来书写上的方便,但不是一种良好的编程
    风格,上例应该改成:
    // 头文件
    class A
    {
    public:
    void Foo(int x, int y);
    }
    // 定义文件
    inline void A::Foo(int x, int y)
    {
    }

    慎用内联
    内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?
    如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?
    内联是以代码膨胀(复制)为代价,仅仅省去了函数调用的开销,从而提高函数的
    执行效率。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收
    获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,
    消耗更多的内存空间。以下情况不宜使用内联:
    (1)如果函数体内的代码比较长,使用内联将导致内存消耗代价较高。
    (2)如果函数体内出现循环,那么执行函数体内代码的时间要比函数调用的开销大。
    类的构造函数和析构函数容易让人误解成使用内联更有效。要当心构造函数和析构
    函数可能会隐藏一些行为,如“偷偷地”执行了基类或成员对象的构造函数和析构函数。
    所以不要随便地将构造函数和析构函数的定义体放在类声明中。
    一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明
    了inline 不应该出现在函数的声明中)。

    C++ 语言支持函数内联,其目的是为了提高函数的执行效率(速度)。
    在C程序中,可以用宏代码提高执行效率。宏代码本身不是函数,但使用起来象函数。
    预处理器用复制宏代码的方式代替函数调用,省去了参数压栈、生成汇编语言的CALL调用、 
    返回参数、执行return等过程,从而提高了速度。 

    使用宏代码最大的缺点是容易出错,预处理器在复制宏代码时常常产生意想不到的边际效应。 

    对于C++ 而言,使用宏代码还有另一种缺点:无法操作类的私有数据成员。 

    让我们看看C++ 的"函数内联"是如何工作的。 
    对于任何内联函数,编译器在符号表里放入函数的声明(包括名字、参数类型、返回值类型)。 
    如果编译器没有发现内联函数存在错误,那么该函数的代码也被放入符号表里。 
    在调用一个内联函数时,编译器首先检查调用是否正确 
    (进行类型安全检查,或者进行自动类型转换,当然对所有的函数都一样)。 
    如果正确,内联函数的代码就会直接替换函数调用,于是省去了函数调用的开销。

    这个过程与预处理有显著的不同,因为预处理器不能进行类型安全检查,或者进行自动类型转换。 
    假如内联函数是成员函数,对象的地址(this)会被放在合适的地方,这也是预处理器办不到的。 

    C++ 语言的函数内联机制既具备宏代码的效率,又增加了安全性,而且可以自由操作类的数据成员。 
    所以在C++ 程序中,应该用内联函数取代所有宏代码,"断言assert"恐怕是唯一的例外。 
    assert是仅在Debug版本起作用的宏,它用于检查"不应该"发生的情况。 
    为了不在程序的Debug版本和Release版本引起差别,assert不应该产生任何副作用。 
    如果assert是函数,由于函数调用会引起内存、代码的变动,那么将导致Debug版本与Release版本存在差异。 
    所以assert不是函数,而是宏。

     

    展开全文
  • inline(内联)函数

    2018-03-22 08:22:37
    关于内联函数的几点:1. 对于那些函数体代码量很小,又经常调用的函数,一般用作内联函数。因为函数体代码很小,函数体执行的时间远小于调用函数的时间,从而提高代码执行效率。2. 一般建议少用宏定义,改用内联函数...

    关于内联函数的几点:

    1.  对于那些函数体代码量很小,又经常调用的函数,一般用作内联函数。因为函数体代码很小,函数体执行的时间远小于调用函数的时间,从而提高代码执行效率。

    2. 一般建议少用宏定义,改用内联函数。因为宏定义容易出错(如边界错误),而且宏定义只是编译时简单的替换,而内联函数含有类型安全检查和自动类型转换,这些是宏定义没有的。宏定义还有另一个缺点:无法操作类的私有数据成员。

    3. 内联支持调试,宏定义不支持调试(assert除外)。宏定义只是简单的替换,内联在debug时相当于普通函数,此时并没有真正的内联,可以参与调试,在release时,才真正内联。

    4. inline关键字是“定义型关键字”,inline只有写在定义前时,才是内联函数,如果inline仅写在声明前,而定义前没有的话,不算内联。

    5. 内联定义一般写在头文件中,若写在源文件中,只能给本源文件使用。若其他源文件要使用,需重写下内联函数的定义,才可使用。而且两源文件中内联函数的定义必须相同。

    换一种说法内联函数应该在头文件中定义,这一点不同于其他函数。编译器在调用点内联展开函数的代码时,必须能够找到 inline 函数的定义才能将调用函数替换为函数代码,而对于在头文件中仅有函数声明是不够的。当然内联函数定义也可以放在源文件中,但此时只有定义的那个源文件可以用它,而且必须为每个源文件拷贝一份定义(即每个源文件里的定义必须是完全相同的),当然即使是放在头文件中,也是对每个定义做一份拷贝,只不过是编译器替你完成这种拷贝罢了。但相比于放在源文件中,放在头文件中既能够确保调用函数是定义是相同的,又能够保证在调用点能够找到函数定义从而完成内联(替换)。)

    6. 在头文件中加入或修改 inline 函数时,使用了该头文件的所有源文件都必须重新编译。

    7. 有些函数即使声明为内联的也不一定会被编译器内联, 这点很重要; 

    8. 慎用内联,有可能造成代码膨胀。


    更新...

    9. 一个函数若声明inline,则每处声明都必须保证是inline,类成员函数若在类定义内给出定义,则隐含inline。


    展开全文
  • C++中的inline用法

    万次阅读 2018-08-12 15:04:33
    1 引入inline关键字的原因 在c/c++中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了inline修饰符,表示为内联函数,栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间...

     

    1 引入inline关键字的原因


    在c/c++中,为了解决一些频繁调用的小函数大量消耗栈空间(栈内存)的问题,特别的引入了inline修饰符,表示为内联函数,栈空间就是指放置程序的局部数据(也就是函数内数据)的内存空间。在系统下,栈空间是有限的,假如频繁大量的使用就会造成因栈空间不足而导致程序出错的问题,如,函数的死循环递归调用的最终结果就是导致栈内存空间枯竭。

     

    下面我们来看一个例子:

     

     

    #include <stdio.h>
    #include<string.h>
    
    // 函数定义为inline即:内联函数
    inline char* inline_test(int num) 
    {
        return (num % 2 > 0) ? "奇" : "偶";
    }
    
    
    int main()
    {
       int i = 0;
       for (i = 1; i < 10; i++) 
       {
           printf("inline_test:   i:%d   奇偶性:%s\n", i, inline_test(i));   
       }
       
       return 0;
    }

     

     

    上面的例子就是标准的内联函数的用法,使用inline修饰带来的好处我们表面看不出来,其实,在内部的工作就是在每个for循环的内部任何调用dbtest(i)的地方都换成了(i%2>0)?”奇”:”偶”,这样就避免了频繁调用函数对栈内存重复开辟所带来的消耗。


    是否内联 可以在编码、编译、连接、甚至是应用程序的安装进行的。
    非运行期,反汇编看看有没有相关的函数调用call没有就是inline了。

     

     

    2 inline使用限制

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

     

     

    3 inline仅是一个对编译器的建议

    inline函数仅仅是一个对编译器的建议,所以最后能否真正内联,看编译器的意思,
    它如果认为函数不复杂,能在调用点展开,就会真正内联,并不是说声明了内联就会内联,声明内联只是一个建议而已。
    幸运的是大多数编译器提供了一个诊断级别:如果它们无法将你要求的函数 inline 化, 会给你一个警告信息。

     

     

     

    4. 建议

    (1) inline函数的定义放在头文件中

    inline 在大多数 C++ 程序中是编译行为。其次,因为内联函数要在调用点展开,所以编译器必须随处可见内联函数的定义,要不然就成了非内联函数的调用了。所以,这要求每个调用了内联函数的文件都出现了该内联函数的定义。因此,将内联函数的定义放在头文件里实现是合适的,省却你为每个文件实现一次的麻烦。

    (2) 声明跟定义要一致
    如果在每个文件里都实现一次该内联函数的话,那么,最好保证每个定义都是一样的,否则,将会引起未定义的行为。如果不是每个文件里的定义都一样,那么,编译器展开的是哪一个,那要看具体的编译器而定。所以,最好将内联函数定义放在头文件中。

    (3) 构造函数和析构函数往往是 inlining 的糟糕候选人

    因为构造函数和析构函数编译器往往做了各式各样的保证。当你创建对象, 每一个基类和成员都会自动构造, 当你释放对象, 每个基类和成员都要自动释放。

     

     

    5 类中的成员函数与inline

     

    类 inline 函数有两种方法:
    (1) 隐喻式:定义在类中的成员函数缺省都是内联的,如果在类定义时就在类内给出函数定义,那当然最好。
    (2) 明确声明:如果在类中未给出成员函数定义,而又想内联该函数的话,那在类外要加上inline,否则就认为不是内联的。


    例如,

    class A
    {
        public:void Foo(int x, int y) {  } // 自动地成为内联函数
    }
    

     

     

    将成员函数的定义体放在类声明之中虽然能带来书写上的方便,但不是一种良好的编程风格,上例应该改成:

     

    // 头文件
    class A
    {
        public:
        void Foo(int x, int y);
    }

     

    // 定义文件
    inline void A::Foo(int x, int y){}

     

     

    6 inline 是一种“用于实现的关键字”

     

    关键字inline 必须与函数定义体放在一起才能使函数成为内联,仅将inline 放在函数声明前面不起任何作用。


    如下风格的函数Foo 不能成为内联函数:

     

    inline void Foo(int x, int y); // inline 仅与函数声明放在一起
    
    void Foo(int x, int y){}

     

    而如下风格的函数Foo 则成为内联函数:

     

    void Foo(int x, int y);
    
    inline void Foo(int x, int y) {} // inline 与函数定义体放在一起

     

    所以说,inline 是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。一般地,用户可以阅读函数的声明,但是看不到函数的定义。尽管在大多数教科书中内联函数的声明、定义体前面都加了inline 关键字,但我认为inline不应该出现在函数的声明中。这个细节虽然不会影响函数的功能,但是体现了高质量C++/C 程序设计风格的一个基本原则:声明与定义不可混为一谈,用户没有必要、也不应该知道函数是否需要内联。

     

     

     

    7 慎用inline


    内联能提高函数的执行效率,为什么不把所有的函数都定义成内联函数?如果所有的函数都是内联函数,还用得着“内联”这个关键字吗?

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


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


    一个好的编译器将会根据函数的定义体,自动地取消不值得的内联(这进一步说明了 inline 不应该出现在函数的声明中)。

     

     


    8 总结


    内联函数并不是一个增强性能的灵丹妙药。只有当函数非常短小的时候它才能得到我们想要的效果;但是,如果函数并不是很短而且在很多地方都被调用的话,那么将会使得可执行体的体积增大。 最令人烦恼的还是当编译器拒绝内联的时候。在老的实现中,结果很不尽人意,虽然在新的实现中有很大的改善,但是仍然还是不那么完善的。一些编译器能够足够的聪明来指出哪些函数可以内联哪些不能,但是大多数编译器就不那么聪明了,因此这就需要我们的经验来判断。如果内联函数不能增强性能,就避免使用它!

     

     

     

     

     

     

     

     

     

     

     

     

     

     

    本文转自:

    https://www.cnblogs.com/fnlingnzb-learner/p/6423917.html

     

     

     

     

     

     

     

     

    展开全文
  • C++ inline 函数简介

    万次阅读 多人点赞 2020-05-25 22:04:53
    1.inline函数简介 inline函数是由inline关键字来定义,引入inline函数的主要原因是用它替代C中复杂易错不易维护的宏函数。 2.编译器对inline函数的处理办法 inline对于编译器而言,在编译阶段完成对...

    1.inline 函数简介

    inline 函数由 inline 关键字定义,引入 inline 函数的主要原因是用它替代 C 中复杂易错不易维护的宏函数。

    2.编译器对 inline 函数的处理办法

    编译器在编译阶段完成对 inline 函数的处理,即对 inline 函数的调用替换为函数的本体。但 inline 关键字对编译器只是一种建议,编译器可以这样去做,也可以不去做。从逻辑上来说,编译器对 inline 函数的处理步骤一般如下:
    (1)将 inline 函数体复制到inline函数调用处;
    (2)为所用 inline 函数中的局部变量分配内存空间;
    (3)将 inline 函数的的输入参数和返回值映射到调用方法的局部变量空间中;
    (4)如果 inline 函数有多个返回点,将其转变为 inline 函数代码块末尾的分支(使用GOTO)。

    比如如下代码:

    //求0-9的平方
    inline int inlineFunc(int num)
    {  
      if(num>9||num<0)
    	  return -1;  
      return num*num;  
    }  
    
    int main(int argc,char* argv[])
    {
    	int a=8;
    	int res=inlineFunc(a);
    	cout<<"res:"<<res<<endl;
    }
    

    inline 之后的 main 函数代码类似于如下形式:

    int main(int argc,char* argv[])
    {
    	int a=8;
    	{  
    	    int _temp_b=8;  
    	    int _temp;  
    	    if (_temp_q >9||_temp_q<0) _temp = -1;  
    	    else _temp =_temp*_temp;  
    	    b = _temp;  
    	}
    }  
    

    经过以上处理,可消除所有与调用相关的痕迹以及性能的损失。inline 通过消除调用开销来提升性能。

    3.inline 函数使用的一般方法

    函数定义时,在返回类型前加上关键字 inline 即把函数指定为内联,函数申明时可加也可不加。但是建议函数申明的时候,也加上 inline,这样能够达到"代码即注释"的作用。

    使用格式如下:

    inline int functionName(int first, int secend,...) {/****/};
    

    inline如果只修饰函数的申明的部分,如下风格的函数foo不能成为内联函数:

    inline void foo(int x, int y); //inline仅与函数声明放在一起
    
    void foo(int x, int y){}
    

    而如下风格的函数foo 则成为内联函数:

    void foo(int x, int y);
    
    inline void foo(int x, int y){} //inline与函数定义体放在一起
    

    4.inline 函数的优点与缺点

    从上面可以知道,inline函数相对宏函数有如下优点:
    (1)内联函数同宏函数一样将在被调用处进行代码展开,省去了参数压栈、栈帧开辟与回收,结果返回等,从而提高程序运行速度。

    (2)内联函数相比宏函数来说,在代码展开时,会做安全检查或自动类型转换(同普通函数),而宏定义则不会。
    例如宏函数和内联函数:

    //宏函数
    #define MAX(a,b) ((a)>(b)?(a):(b))
    
    //内联函数
    inline int MAX(int a,int b)
    {
    	return a>b?a:b;
    }
    

    使用宏函数时,其书写语法也较为苛刻,如果对宏函数出现如下错误的调用,MAX(a,"Hello"); 宏函数会错误地比较int和字符串,没有参数类型检查,但是使用内联函数的时候,会出现类型不匹配的编译错误。

    (3)在类中声明同时定义的成员函数,自动转化为内联函数,因此内联函数可以访问类的成员变量,宏定义则不能。

    (4)内联函数在运行时可调试,而宏定义不可以。

    万事万物都有阴阳两面,内联函数也不外乎如此,使用inline函数,也要三思慎重。inline函数的缺点总结如下:
    (1)代码膨胀。
    inline函数带来的运行效率是典型的以空间换时间的做法。内联是以代码膨胀(复制)为代价,消除函数调用带来的开销。如果执行函数体内代码的时间,相比于函数调用的开销较大,那么效率的收获会很少。另一方面,每一处内联函数的调用都要复制代码,将使程序的总代码量增大,消耗更多的内存空间。

    (2)inline 函数无法随着函数库升级而升级。
    如果f是函数库中的一个inline函数,使用它的用户会将f函数实体编译到他们的程序中。一旦函数库实现者改变f,所有用到f的程序都必须重新编译。如果f是non-inline的,用户程序只需重新连接即可。如果函数库采用的是动态连接,那这一升级的f函数可以不知不觉的被程序使用。

    (3)是否内联,程序员不可控。
    inline函数只是对编译器的建议,是否对函数内联,决定权在于编译器。编译器认为调用某函数的开销相对该函数本身的开销而言微不足道或者不足以为之承担代码膨胀的后果则没必要内联该函数,若函数出现递归,有些编译器则不支持将其内联。

    5.inline函数的注意事项

    了解了内联函数的优缺点,在使用内联函数时,我们也要注意以下几个事项和建议。

    (1)使用函数指针调用内联函数将会导致内联失败。
    也就是说,如果使用函数指针来调用内联函数,那么就需要获取inline函数的地址。如果要取得一个inline函数的地址,编译器就必须为此函数产生一个函数实体,那么就内联失败。

    (2)如果函数体代码过长或者有多重循环语句,if或witch分支语句或递归时,不宜用内联。

    (3)类的 constructors、destructors 和虚函数往往不是 inline 函数的最佳选择。
    类的构造函数(constructors)可能需要调用父类的构造函数,析构函数同样可能需要调用父类的析构函数,二者背后隐藏着大量的代码,不适合作为inline函数。虚函数(destructors)往往是运行时确定的,而inline是在编译时进行的,所以内联虚函数往往无效。如果直接用类的对象来使用虚函数,那么对有的编译器而言,也可起到优化作用。

    (4)至于内联函数是定义在头文件还是源文件的建议。
    内联展开是在编译时进行的,只有链接的时候源文件之间才有关系。所以内联要想跨源文件必须把实现写在头文件里。如果一个 inline 函数会在多个源文件中被用到,那么必须把它定义在头文件中。

    // base.h
    class Base{protected:void fun();};
    
    // base.cpp
    #include base.h
    inline void Base::fun(){}
    
    //derived.h
    #include base.h
    class Derived: public Base{public:void g();};
    
    // derived.cpp
    void Derived::g(){fun();} //VC2010: error LNK2019: unresolved external symbol
    

    上面这种错误,就是因为内联函数 fun() 定义在编译单元 base.cpp 中,那么其他编译单元中调用fun()的地方将无法解析该符号,因为在编译单元 base.cpp 生成目标文件 base.obj 后,内联函数fun()已经被替换掉,编译器不会为 fun() 生成函数实体,链接器自然无法解析。所以如果一个 inline 函数会在多个源文件中被用到,那么必须把它定义在头文件中。

    这里有个问题,当在头文件中定义内联函数,那么被多个源文件包含时,如果编译器因为 inline 函数不适合被内联时,拒绝将inline函数进行内联处理,那么多个源文件在编译生成目标文件后都将各自保留一份inline函数的实体,这个时候程序在链接阶段会出现重定义错误吗?答案是不会,原因是,链接器在链接的过程中,会删除多余的inline函数实体,只保留一份,所以不会报重定义错误,因此我们不需要使用 static 关键字去多余地修饰inline函数,即不必像下面这样。

    //test.h
    static inline int max(int a,int b)
    {
    	return a>b?a:b;
    }
    

    (5)能否强制编译器进行内联操作?
    也有人可能会觉得能否强制编译器进行函数内联,而不是建议编译器进行内联呢?很不幸的是目前还不能强制编译器进行函数内联,如果使用的是 MS VC++, 注意 __forceinline 如同 inine 一样,也是一个用词不当的表现,它只是对编译器的建议比inline更加强烈,并不能强制编译器进行inline操作。

    (6)如何查看函数是否被内联处理了?
    在 VS2017 中查看预处理后的.i文件,发现inline函数的内联处理不是在预处理阶段,而是在编译阶段。将源文件编译为汇编代码,或者将可执行文件反汇编生成汇编代码,在汇编代码中查看inline函数被调用处是否出现汇编的call指令,如果没有则说明inline函数在被调用处进行了函数体的替换操作,即内联处理。具体可以参考内联函数到底有没有被嵌入到调用处呢?

    (7)C++类成员函数定义在类体内为什么不会报重定义错误?
    类成员函数定义在类体内,并随着类的定义放在头文件中,当被不同的源文件包含,那么每个源文件都应该包含了类成员函数的实体,为何在链接的过程中不会报函数的重定义错误呢?

    原因是在类里定义时,这种函数会被编译器编译成内联函数,在类外定义的函数则不会。内联函数的好处是加快程序的运行速度,缺点是会增加程序的尺寸。比较推荐的写法是把一个经常要用的而且实现起来比较简单的小型函数放到类里去定义,大型函数最好还是放到类外定义。

    可能存在疑问,类体内的成员函数被编译器内联处理,但并不是所有的成员函数都会被内联处理,比如包含递归的成员函数。但是实际测试,将包含递归的成员函数定义在类体内,被不同的源文件包含并不会报重定义错误,为什么会这样呢?请保持着疑问与好奇心,请继续往下看。

    如果编译器发现被定义在类体内的成员函数无法被内联处理,那么在程序的链接过程中也不会出现函数重定义的错误。其原因是什么呢?其实很简单,类体内定义的成员函数即使不被内联处理,在链接时,链接器会对重复的成员函数实体进行冗余优化,只保留一份函数实体,也就不会出现函数重定义的错误了。

    除了 inline 函数,C++编译器在很多时候都会产生重复的代码,比如模板(Templates)、虚函数表(Virtual Function Table)、类的默认成员函数(构造函数、析构函数和赋值运算符)等。以函数模板为例,在多个源文件中生成相同的实例,链接时不会出现函数重定义的错误,实际上是一个道理,因为链接器会对重复代码进行删除,只保留一份函数实体。

    6.小结

    可以将内联理解为 C++ 中对于函数专有的宏,对于 C 的函数宏的一种改进。对于常量宏,C++ 提供 const 替代;而对于函数宏,C++ 提供的方案则是 inline。C++ 的内联机制,既具备宏代码的效率,又增加了安全性,还可以自由操作类的数据成员,算是一个比较完美的解决方案。

    上面的结论和观点,缺乏实践和权威资料支撑,难免存在错误,仅供参考学习,如果大家发现错误和需要改进的地方,请大家留言给予宝贵的建议。


    参考文献

    [1] inline函数
    [2] 小问题大思考之C++里的inline函数
    [3] 把inline函数的定义放在头文件中
    [4] Inline Functions (C++)
    [5] Can I selectively (force) inline a function?
    [6] C语言inline详细讲解
    [7] C++中的作用域与生命周期
    [8] 内联函数到底有没有被嵌入到调用处呢?
    [9] 余甲子,石凡,潘爱民.程序员的自我修养——链接、装载与库[M].北京:机械工业出版社,2009.C4.4.1重复代码消除.P113-P114

    展开全文
  • __inline 关键字使用

    千次阅读 2018-07-05 22:44:21
    inline关键字是用于函数声明或定义,可以把函数指定为内联函数,而且关键字inline必须与函数定义放在一起才能使函数成为内联,仅仅将inline放在函数声明前是不起任何作用的。 inline的作用是什么呢?为什么要引入...
  • __inline 关键字建议编译器在合理的情况下内联编译 C 或 C++ 函数。...__inline 语义与 C++ inline 关键字的语义完全相同。 __inline 是一个存储类限定符。 它不影响函数的类型。 格式: inline
  • HTML中display:inline;特性

    千次阅读 2018-05-24 21:30:52
    display属性inline内嵌式布局特点:1.可以支持同行排列2.不支持宽高的设置,不支持上下margin设置,支持左右margin的设置,大小由内部的文字撑开3.内部的标签的只能是文字或者Inline型标签,项目中的inline主要用来套文字...
  • inline函数

    千次阅读 2019-05-18 14:47:39
    什么是inline函数 一个函数的程序进行代码拓展而不被调用,用相应的函数代码替换函数调用。 引入inline函数的原因 系统中会有这样的场景:for循环调用一个处理函数或则是递归调用一些算法。因为调用一个任意函数...
  • 关于c中的inline

    万次阅读 多人点赞 2011-06-04 23:31:00
    在c中,为了解决一些频繁调用的小函数大量消耗栈空间或是叫栈内存的问题,特别的引入了inline修饰符,表示为内联函数。栈空间就是指放置程式的局部数据也就是函数内数据的内存空间,在系统下,栈空间是有限的,假如...
  • 内联函数 —— C 中关键字 inline 用法解析

    万次阅读 多人点赞 2016-03-13 13:37:40
     在C语言中,如果一些函数被频繁调用,不断地有函数入栈,即函数栈,会造成栈空间或栈内存的大量消耗,为了解决,特别的引入了inline修饰符,表示为内联函数。  栈空间就是指放置程式的局部数据也就是函数内数据的...
  • 内联函数(inline)总结

    万次阅读 2016-01-30 20:15:40
    1:定义:   它们看起来象函数,运作起来象函数,比宏(macro)要好得多,使用时... inline关键字必须和函数体定义放在一起才可以实现内联,仅仅将inline放在函数声明之前不起任何作用。inline是一个用于实现的关键字
  • inline,static inline

    千次阅读 2019-04-24 09:18:55
    inline:在函数声明或定义中函数返回类型前加上关键字inline,即可以把函数指定为内联函数。 内联函数:建议编译器对一些特殊函数进行内联扩展(有时称作在线扩展)。也就是说建议编译器将指定的函数体插入并取代每...
  • inline函数 :在代码里加上inline后,符号解析出现错误, inline函数 :在函数的调用直接代码展开(编译阶段 ) 宏和inline函数有什么区别??? inline函数的优点: 在函数的调用直接展开,没有函数的请栈和开栈 ...
  • 实现Android ARM64平台下Inline Hook框架

    万次阅读 2017-10-16 18:55:33
    Android阵营新出机型的cpu基本都是64位了,虽然...但是整个安卓生态圈似乎还没有开源发布的ARM64内联HOOK方案,所以自己动手写了个,姑且取名And64InlineHook吧,需要注意的是仍然是Alpha版。  关于Inline Hook的背
  • C++inline函数简介

    2019-06-03 09:36:13
    1.inline函数简介 inline函数是由inline关键字来定义,引入inline函数的主要原因是用它替代C中复杂易错不易维护的宏函数。 inline(小心,不是online),翻译成“内联”或“内嵌”。意指:当编译器发现某段代码在...
  • matlab中inline的用法

    万次阅读 2012-11-15 14:42:10
    在matlab中,可以用inline把串转成函数,代码如下: clear clc f = inline('a * x * x + b * x + c', 'a', 'b','c', 'x') f(1, 2, 3, 1)  结果为: f =  Inline function:  f(a,b,c,x) = a * x * x...
  • inline
  • block、inlineinline-block的区别

    千次阅读 2019-01-15 21:14:58
    一、display:block特点 1、独占一行,多个block元素另起一行,默认情况下,block元素宽度自动填满其父元素宽度 2、block元素可以设置width,...1、inline元素不会独占一行,多个相邻的行内元素会排列在同一行里,直到...
  • C语言inline函数说明

    千次阅读 2018-11-03 22:13:27
    一句话总结:inline函数的定义(而不是申明)一般必须在头文件或本C文件内使用之前。 inline是一种“用于实现的关键字”,而不是一种“用于声明的关键字”。关键字inline必须与函数实现放在一起才能使函数成为内联...
  • Inline Hook 之(监视任意函数)

    万次阅读 热门讨论 2020-07-23 18:39:08
    前面已经写过两次inline hook的博文了,第一篇为:《C/C++ HOOK API(原理深入剖析之-LoadLibraryA)》,这篇博文的方法是通过修改任意函数的前面N个字节,实现跳转并进入到我们自定义的hook函数里,执行完毕我们的...
1 2 3 4 5 ... 20
收藏数 585,635
精华内容 234,254
关键字:

inline