跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书GitHub 精选镜像AI 生图工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++算法

C++ inline 关键字详解:原理、使用与验证

C++ inline 关键字用于请求编译器将函数体内联展开以减少调用开销,适用于小函数且定义应置于头文件。编译器可能因函数大小、复杂度及优化级别忽略该请求。可通过汇编代码检查函数标签或使用编译器优化信息参数验证内联是否生效。

漫步发布于 2026/3/16更新于 2026/8/2256 浏览
C++ inline 关键字详解:原理、使用与验证

inline 是一个请求(而非命令)

inline 关键字用于向编译器发出一个请求,建议将函数体在每个调用点内联展开。这意味着编译器在编译过程中,可能会将函数的代码直接插入到调用该函数的地方,而不是通过通常的函数调用机制来执行。

需要注意的是,inline 只是一个建议,编译器可以选择是否接受这个建议。编译器可能会基于多种因素(如函数的大小、复杂性、调用频率以及整体代码的优化目标)来决定是否进行内联展开。

inline 函数通常用于小函数

inline 函数通常用于那些执行速度快且调用频繁的小函数。这些函数通常只有几行代码,并且不包含复杂的控制结构或大量的计算。

通过将这些小函数内联展开,可以减少函数调用的开销(如栈帧的创建和销毁、参数传递等),从而提高程序的执行效率。

对于较大的函数或包含复杂逻辑的函数,内联展开可能会导致代码膨胀,甚至可能降低性能。

inline 函数的定义通常放在头文件中

由于 inline 函数需要在每个调用点展开,因此其定义需要在编译时对每个编译单元可见。这通常意味着 inline 函数的定义应该放在头文件中,而不是源文件(.c)中。这样做可以确保在链接时不会出现重复定义的问题,因为每个编译单元都会包含 inline 函数的定义,并且编译器会处理这些重复的定义。

如果 inline 函数在多个编译单元中被引用,并且没有通过 static 关键字限制其链接性,那么在某些编译器和链接器实现中可能会遇到链接错误。为了避免这种情况,通常建议将 inline 函数声明为 static,从而限制其在单个编译单元内的可见性。

inline 函数不能包含复杂的控制结构

inline 函数通常应该避免包含复杂的控制结构,如循环和递归。这是因为内联展开这些结构可能会导致代码膨胀,增加程序的内存占用,并且可能不会带来性能上的提升。

特别是递归函数,由于递归调用本身的开销和栈空间的使用,内联展开通常是不合适的。

对于包含复杂控制结构的函数,即使它们很小,编译器也可能选择不进行内联展开。

编译器可能忽略 inline 请求

编译器可能会忽略 inline 请求,特别是在以下情况下:

  • 函数体较大:如果函数体包含大量代码,编译器可能会认为内联展开会导致代码膨胀,从而选择不进行内联。
  • 包含复杂逻辑:如果函数包含复杂的控制结构、大量的计算或条件分支,编译器可能会认为内联展开不会带来性能上的优势,甚至可能降低性能。
  • 优化级别:编译器的优化级别也会影响其是否接受 inline 请求。在较低的优化级别下,编译器可能会更加保守地选择不进行内联展开。
  • 链接时优化:在某些情况下,即使函数在源代码中被标记为 inline,编译器也可能在链接时决定不进行内联展开。这取决于编译器的链接时优化能力和策略。

验证是否 inline

代码示例

#include <stdio.h>
#include <time.h>
#include <stdint.h>

// 定义一个 inline 函数
inline int add_inline(int a, int b) {
    return a + b;
}

// 定义一个普通函数
int add_normal(int a, int b) {
    return a + b;
}

int main() {
    const double N = 10000000000000000; // 函数调用次数
    clock_t start, end;
    double cpu_time_used;

    // 测试普通函数
    start = clock();
    for (double i = 0; i < N; i += 0.0000000001) {
        add_normal(i, i);
    }
    end = clock();
    cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
    printf("Normal function took %f seconds to execute \n", cpu_time_used);

    // 测试 inline 函数
    start = clock();
    for (double i = 0; i < N; i += 0.0000000001) {
        add_inline(i, i);
    }
    end = clock();
    cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
    printf("Inline function took %f seconds to execute \n", cpu_time_used);

    return 0;
}

汇编代码分析

add_normal(int, int):
    lea eax,[rdi+rsi*1]
    ret
data16 data16 cs nop WORD PTR [rax+rax*1+0x0]
main:
    push rbx
    call 1040 <clock@plt>
    mov rbx,rax
    call 1040 <clock@plt>
    sub rax,rbx
    cvtsi2sd xmm0,rax
    divsd xmm0,QWORD PTR [rip+0xe8a] # 2008 <_IO_stdin_used+0x8>
    lea rdi,[rip+0xe8b] # 2010 <_IO_stdin_used+0x10>
    mov al,0x1
    call 1030 <printf@plt>
    call 1040 <clock@plt>
    mov rbx,rax
    call 1040 <clock@plt>
    sub rax,rbx
    xorps xmm0,xmm0
    cvtsi2sd xmm0,rax
    divsd xmm0,QWORD PTR [rip+0xe5c] # 2008 <_IO_stdin_used+0x8>
    lea rdi,[rip+0xe8a] # 203d <_IO_stdin_used+0x3d>
    mov al,0x1
    call 1030 <printf@plt>
    xor eax,eax
    pop rbx
    ret

代码中有 add_normal 的标签,却没有 add_line 的标签。我们可以通过汇编代码查看是否被 inline,汇编代码中,被内联的函数不会有函数的标签,普通的函数会有函数标签。具体详见:https://godbolt.org/z/jjGrjW85q(注意,要使用-O2 编译)。

其他验证方法

也可以通过 gcc 编译器,搭配 -fopt-info 参数,输出编译器的所有优化信息:https://godbolt.org/z/4Ycx35hTh,如图:

Output of x86-64 gcc 15.1 (Compiler #1)
<source>:32:19: optimized: Inlining int add_inline(int, int)/13 into int main()/15.
<source>:23:19: optimized: Inlining int add_normal(int, int)/14 into int main()/15.
ASM generation compiler returned: 0
<source>:32:19: optimized: Inlining int add_inline(int, int)/13 into int main()/15.
<source>:23:19: optimized: Inlining int add_normal(int, int)/14 into int main()/15.
Execution build compiler returned: 0
Program returned: 0
Normal function took 0.000001 seconds to execute
Inline function took 0.000001 seconds to execute

参考资料

  • https://stackoverflow.com/questions/10631283/how-will-i-know-whether-inline-function-is-actually-replaced-at-the-place-where
  • https://stackoverflow.com/questions/31108159/what-is-the-use-of-the-inline-keyword-in-c

目录

  1. inline 是一个请求(而非命令)
  2. inline 函数通常用于小函数
  3. inline 函数的定义通常放在头文件中
  4. inline 函数不能包含复杂的控制结构
  5. 编译器可能忽略 inline 请求
  6. 验证是否 inline
  7. 代码示例
  8. 汇编代码分析
  9. 其他验证方法
  10. 参考资料
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 用 Prompt 生成正则表达式进行文本匹配实战指南
  • 三维组合导航算法:INS与GNSS融合及卡尔曼滤波MATLAB实现
  • OpenClaw 对接飞书机器人:消息无响应与 Gateway 断开排查
  • 零基础学习 Python:从入门到精通的学习路线与时间规划
  • Linux 网络基础概念:从协议到模型详解
  • CLAUDE.md 与 AGENTS.md 配置指南:让 AI 编程助手理解你的项目
  • System Verilog 硬件验证实战:从基础语法到高级应用
  • 大模型高效推理与部署技术实战
  • AI开发环境搭建:PyTorch/TensorFlow与电科金仓KES连接实战
  • Android 手机端 Python 开发指南:Termux 环境搭建与实战
  • Git 与 TortoiseGit 安装配置实战指南
  • Python 与 Excel 数据分析效率对比:性能差异实测
  • SQL Server 表行转列方法详解
  • Spring Web MVC 入门:从概念到实践
  • 基于 Higress 将 REST API 转换为 MCP Server
  • C++ 哈希表原理与 STL 底层实现解析
  • AI 工具提升产品经理工作效率实战指南
  • 昇腾平台 DeepSeek-R1 与 Qwen2.5 强化学习训练优化实践
  • 10 款常用网络安全渗透测试工具详解
  • Java 集合框架中 HashSet、HashMap、TreeSet 与 TreeMap 的关系解析

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online