C++面试基础系列-inline内联

系列文章目录


文章目录

  • 系列文章目录
  • C++面试基础系列-inline内联
    • Overview
    • 1.inline介绍
      • 1.定义内联函数
      • 2.内联函数的声明与定义
      • 3.编译器的自由裁量权
      • 4.内联变量
      • 5.模板函数自动内联
      • 6.内联汇编
      • 7.内联命名空间
      • 8.内联函数的限制
      • 9.内联函数的性能
      • 10.显式内联与隐式内联
    • 2.inline使用方法
      • 2.1.使用方法
      • 2.2.作用原理
      • 2.3.注意事项
    • 关于作者


C++面试基础系列-inline内联

Overview

  • inline可以在头文件中声明和定义函数或变量
  • 不违反一次定义规则(One Definition Rule, ODR)
  • 会加快程序运行速度(避免函数调用的开销,如建立栈帧、传递参数等操作),但会增加代码ROM使用

1.inline介绍

在C++中,inline关键字是一种函数或变量的声明属性,它请求编译器在编译时将函数或变量的定义嵌入到每个使用该函数或变量的地方,从而避免函数调用的开销。使用inline可以提高程序的执行效率,尤其是在调用小型函数时。

以下是inline的一些关键点和用法:

1.定义内联函数

内联函数是在定义时使用inline关键字声明的函数。编译器会尝试将这些函数的定义直接嵌入到调用点,从而减少函数调用的开销。

inline int add(int a, int b) {
    return a + b;
}

2.内联函数的声明与定义

内联函数通常在头文件中声明和定义,这样它们的定义可以被多个编译单元(.cpp文件)包含,而不会违反一次定义规则(One Definition Rule, ODR)。

3.编译器的自由裁量权

编译器对是否内联一个函数有最终决定权。即使使用了inline关键字,编译器也可能出于优化或其他原因选择不内联该函数。

4.内联变量

inline也可以用于变量,特别是对于常量表达式。内联变量的定义可以在多个编译单元中使用,而不违反ODR。

inline const int MAX_SIZE = 1024;

5.模板函数自动内联

模板函数在实例化时通常会被编译器视为内联,即使没有显式地使用inline关键字。

template<typename T>
T maximum(T a, T b) {
    return (a > b) ? a : b;
}

6.内联汇编

inline还可以与汇编语言一起使用,允许在C++代码中嵌入汇编指令。

inline int readFlag() {
    int flag;
    asm volatile("in %1, %0" : "=a"(flag) : "dN"(0x01)); // x86特定汇编
    return flag;
}

7.内联命名空间

C++17引入了内联命名空间,它允许在不同的编译单元中使用相同的命名空间名称而不会引起冲突。

inline namespace experimental {
    void func() {
        // ...
    }
}

8.内联函数的限制

内联函数有一些限制,例如它们不能包含循环、跳转语句(如goto)、递归调用等复杂结构。

9.内联函数的性能

内联函数可以减少函数调用的开销,但同时也会增加代码的大小。如果内联函数体较大,可能会导致缓存失效(cache misses),从而降低程序的运行效率。

10.显式内联与隐式内联

从C++11开始,如果编译器决定不内联一个inline函数,它将作为普通的非内联函数调用。而在C++11之前,如果编译器不内联inline函数,它将完全忽略该函数的定义。

使用inline可以提高程序的性能,但应当谨慎使用,以避免不必要的代码膨胀。在某些情况下,现代编译器的优化选项(如GCC的-O2-O3)可能会自动内联适当的函数,而不需要显式地使用inline关键字。

2.inline使用方法

在 C++中,inline关键字用于向编译器建议在适当的地方将函数展开,以减少函数调用的开销。以下是关于inline的详细介绍:

2.1.使用方法

当定义一个函数时,可以在函数返回类型前加上inline关键字。例如:

inline int add(int a, int b) {
    return a + b;
}

2.2.作用原理

当编译器看到inline函数时,它可能会选择在调用该函数的地方直接将函数体的代码插入,而不是进行传统的函数调用。这样可以避免函数调用的开销,如建立栈帧、传递参数等操作。

例如,在没有使用inline的情况下,函数调用可能会生成如下汇编代码:

push parameter1
push parameter2
call add_function
add esp, 8 ; 清理栈

而如果编译器将inline函数展开,可能的代码会是:

mov eax, parameter1
add eax, parameter2

2.3.注意事项

  1. 编译器不一定会按照inline的建议进行函数展开。编译器会根据函数的复杂程度、调用次数等因素来决定是否展开函数。如果函数过于复杂,编译器可能会忽略inline关键字。
  2. inline函数的定义通常应该放在头文件中。这是因为当多个源文件包含同一个头文件并使用inline函数时,编译器需要在每个源文件中看到函数的定义才能进行展开。如果inline函数的定义只在一个源文件中,而其他源文件只看到函数声明,编译器可能无法进行展开。
  3. 虽然inline可以减少函数调用开销,但过度使用可能会导致代码膨胀。如果函数体很大,展开多个函数调用可能会使生成的目标代码变得很大,从而占用更多的内存。

总的来说,inline是一个有用的关键字,可以在适当的情况下提高程序的性能,但需要谨慎使用。


关于作者

  • 微信公众号:WeSiGJ
  • GitHub:https://github.com/wesigj/cplusplusboys
  • CSDN:https://blog.csdn.net/wesigj
  • 微博:
  • -版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

你可能感兴趣的:(C++,c++,面试,java)