• 第6课


    第6课 - 内联函数分析

    0. 回顾C中的带参函数、宏和内联函数

      带参函数 内联函数
    优点 编译器会做参数的静态类型检查

    原地展开,没有调用开销;

    并且在预处理阶段完成,不占用编译时间。

    函数代码被装入符号表中,在使用时进行替换;

    没有调用开销,效率高,会进行参数类型检查

    缺点

    需要传参、栈变量的开辟和销毁

    压栈、跳转、返回开销;

    不进行类型检查,多次宏替换会导致代码体积变大;

    一些参数的副作用会导致得出错误的结果。

    函数代码较长,使用内联将消耗过多内存;

    函数体内有循环,执行代码的时间比较长。

    1. 常量与宏回顾

      (1)C++中的const常量可以替代宏常数定义,如:  const int A = 3; ←→ #define A  3

      (2)C++中是否有解决方案,可以用来替代宏代码片段呢?

    2. 内联函数

    2.1 内联函数的定义

      (1)C++编译器可以将一个函数进行内联编译,被C++编译器内联编译的函数叫内联函数

      (2)C++中使用 inline 关键字声明内联函数。如:

        

      (3)内联函数声明时inline关键字必须和函数定义结合在一起,否则编译器会直接忽略内联请求。

      (4)C++中推荐使用内联函数替代宏代码片段

    2.2 内联函数的特点

      (1)内联函数具有普通函数的特征(参数检查返回类型等)

      (2)C++编译器直接将内联函数的函数体插入到函数调用的地方

      (3)内联函数没有普通函数调用时的额外开销(压栈、跳转、返回)

      (4)C++编译器也不一定满足函数的内联请求,函数的内联请求可能被编译器拒绝

                 

              图1:编译器拒绝inline请求(仍为函数调用)            图2:函数体被嵌入到调用的地方

     1 #include <stdio.h>
     2 
     3 #define FUNC(a, b) ((a) < (b) ? (a) : (b))
     4 
     5 //MSVC下:要让inline、__forceinline生效必须得做如下的设置:
     6 //①在"项目" → "配置属性" → "C/C++" → "优化" → "内联函数扩展"中选择"只适用于__inline(/ Ob1)"
     7 //②在"配置属性" → "C/C++" → "常规" → "调试信息格式"中选择"程序数据库( / Zi)"
     8 
     9 inline int func(int a, int b)
    10 {
    11     return a < b ? a : b;
    12 }
    13 
    14 int main(int argc, char *argv[])
    15 {
    16     int a = 1;
    17     int b = 3;
    18 
    19     /*
    20     int c = FUNC(++a, b);  //相当于(++a)<(b)?:(++a):(b);
    21 
    22     printf("a = %d
    ", a); //3
    23     printf("b = %d
    ", b); //3
    24     printf("c = %d
    ", c); //3
    25     */
    26 
    27     int c = func(++a, b);
    28 
    29     printf("a = %d
    ", a);     //2
    30     printf("b = %d
    ", b);        //3
    31     printf("c = %d
    ", c);     //2
    32     
    33     return 0;
    34 }
    内联函数初探

    2.3 内联函数与宏的不同

      内联函数
    处理方式 预处理器处理,只是进行简单的文本替换

    编译器处理,会将函数体嵌入到调用的地方。

    但内联请求也可能被编译器拒绝

    类型检查 不做类型检查 具有普通函数的特征,会进行参数和返回类型的检查
    副作用

    2.4 现代C++编译器对内联函数的优化

      (1)现代C++编译器能够进行编译优化,一些函数即没有inline声明,也可能被内联编译

      (2)一些现代的C++编译器提供了扩展语法,可用下列列关键字替代inline来对函数进行强制内联,如:

          ① g++:__atrribute__((always_inline))属性

          ② MSVC:__forceinline

     1 #include <stdio.h>
     2 
     3 //MSVC2013下:在函数声明或定义前加inline或__forceinline都可以
     4 //同时,这两个的表现行为几乎一模一样。只不过__forceinline是MS
     5 //下的,而inline是标准C++的,可移植性更高。
     6 
     7 //__forceinline
     8 //__attribute__((always_inline))
     9 //inline
    10 int add_inline(int n); 
    11 
    12 int main()
    13 {
    14     int r = add_inline(10);
    15 
    16     printf("r = %d
    ", r);
    17 
    18     return 0;
    19 }
    20 
    21 __forceinline int add_inline(int n)
    22 {
    23     int ret = 0;
    24 
    25     for (int i = 0; i < n; i++)
    26     {
    27         ret += i;
    28     }
    29 
    30     return ret;
    31 }
    内联函数深度示例

    3. C++中inline内联编译的限制

      最新的C++编译器只要函数体不是太夸张都可以强制内联成功。列出下面这些是因为工作中使用的C++编译器版本可能较低,无法满足。

      (1)不能存在任何形式的循环语句

      (2)不能存在过多的条件判断语句

      (3)函数体不能过于庞大

      (4)不能对函数进行取址操作

      (5)函数内联声明必须在调用语句之前

    4. 小结

      (1)C++中可以通过 inline 声明内联函数

      (2)编译器直接将内联函数体扩展到函数调用的地方

      (3)inline只是一种请求,编译器不一定允许这种请求

      (4)内联函数省去了函数调用时压栈跳转返回的开销

  • 相关阅读:
    个性化推荐系统(二)---构建推荐引擎
    个性化推荐系统(一)---今日头条等的内容划分、分类
    双11线上压测netty内存泄露
    数据、信息、知识、智慧
    ReentrantLock的相关方法使用
    公平锁和非公平锁
    Lock中使用Condition实现等待通知
    使用IO流将数据库中数据生成一个文件,结果使用Notepad++打开部分数据结尾出现NUL
    ThreadLocal的使用
    join方法
  • 原文地址:https://www.cnblogs.com/shiwenjie/p/7121504.html
Copyright © 2020-2023  润新知