当前位置: 首页 > java >正文

【C++ 初级工程师面试--5】inline内联函数特点 、和普通函数的区别、什么时候适合内联?

文章目录

  • 1 内联函数(inline)特点
  • 2 普通函数调用过程,对比分析开销
    • 2.1 ret = sum(a, b);的执行过程
    • 2.2 ret2 = a + b;的执行过程
  • 3 何时适合内联
  • 4 优化效果分析(原代码改进版)
  • 5 总结建议
    • 5.1 推荐内联‌:
    • 5.1 避免内联‌
    • 5.3 注意事项‌

1 内联函数(inline)特点

// 适合内联的典型场景
inline int sum(int x, int y) { return x + y; }int main() {int a = 10, b = 20;int ret = sum(a, b);  // 可能被优化为 ret = 30int ret2 = a + b;     // 与内联效果等价return 0;
}
  • 1 编译期展开‌:函数体直接嵌入调用处,消除函数调用开销(无压栈/跳转/返回操作)

  • 2 代码膨胀‌:多次调用会导致重复嵌入,增大二进制体积

  • 3 优化友好‌:允许跨语句优化(如常量传播、死代码消除)

  • 4 与普通函数的区别

特性内联函数普通函数
执行机制代码直接展开通过call/ret指令调用
性能影响减少调用开销,可能增大代码体积有调用开销,代码体积更小
调试支持难以单步调试可正常调试
适用场景小函数(1-5行)复杂逻辑函数

inline内联函数:在编译过程中,6就没有函数的调用开销了,在函数的调用点直接把函数的代码进行展开处理了;

inline内联成功了,函数不再生成相应的函数符号;

inline只是建议编译器把这个函数处理成内联函数,

但是不是所有的inline都会被编译器处理成内联函数—如,递归,

debug版本上,inline是不起作用的(如果debug起作用了,调用的函数直接被展开替换了,就没法调试了);inline只有在release版本下才能起作用;

g++ -c main.cpp -02obidump-t main.o

2 普通函数调用过程,对比分析开销

#include<iostream>
using namespace std;int sum(int x, int y)
{return x + y;
}int main()
{int a = 10;int b = 20;//此处有标准的函数调用过程参数压栈,函数栈帧的开辟和回退过程int ret = sum(a, b);// 无调用开销int ret2 = a +  b;return 0;
}

下面是从汇编角度写出ret和ret2的执行过程分析(基于x86架构和cdecl调用约定)

2.1 ret = sum(a, b);的执行过程

; 参数压栈(从右向左)
mov eax, [ebp-8]    ; 加载b的值到eax(假设b在[ebp-8])
push eax             ; 参数y入栈(栈顶方向为低地址)
mov ecx, [ebp-4]     ; 加载a的值到ecx(假设a在[ebp-4])
push ecx             ; 参数x入栈; 函数调用
call sum             ; 1) 将下条指令地址压栈 2) 跳转到sum; sum函数内部执行
sum:push ebp           ; 保存调用者栈帧基址mov ebp, esp       ; 设置新栈帧基址mov eax, [ebp+8]   ; 取参数x(当前ebp+8指向第一个参数)add eax, [ebp+12]  ; 加参数y(ebp+12指向第二个参数)pop ebp            ; 恢复调用者栈帧ret                ; 弹出返回地址并跳转; 调用后处理
add esp, 8           ; 清理参数栈空间(2int8字节)
mov [ebp-12], eax    ; 存储返回值到ret变量(假设ret在[ebp-12]

2.2 ret2 = a + b;的执行过程

mov eax, [ebp-4]     ; 加载a的值到eax
add eax, [ebp-8]     ; 直接加b的值
mov [ebp-16], eax    ; 存储结果到ret2(假设ret2在[ebp-16]

3 何时适合内联

// 适合内联的典型场景(原sum函数)
inline int sum(int x, int y) { return x + y;  // 简单操作且频繁调用
}// 不适合内联的场景
int complexCalc(int x) {// 包含循环/递归等复杂逻辑for(int i=0; i<100; ++i) x *= 2;return x;
}

4 优化效果分析(原代码改进版)

优化前

#include<iostream>
using namespace std;int sum(int x, int y)
{return x + y;
}int main()
{int a = 10;int b = 20;//此处有标准的函数调用过程参数压栈,函数栈帧的开辟和回退过程int ret = sum(a, b);// 无调用开销int ret2 = a +  b;return 0;
}

原代码改进版

inline int sum(int x, int y) { return x + y; }int main() {int a = 10, b = 20;int ret = sum(a, b);  // 可能被优化为 ret = 30int ret2 = a + b;     // 与内联效果等价return 0;
}

编译后可能产生的优化‌:

  1. 内联展开后,ret和ret2的计算会被识别为相同表达式
  2. 常量传播可能直接优化为mov [ret], 30和mov [ret2], 30
  3. 若禁用优化,内联版本仍避免函数调用开销

5 总结建议

5.1 推荐内联‌:

  • 简单存取函数(如getter/setter);
  • 高频调用的小函数(如原sum函数);
  • 模板函数(必须内联);

5.1 避免内联‌

  • 函数体超过10行;
  • 含递归/循环等复杂控制流;
  • 虚函数(动态绑定必须通过函数指针);

5.3 注意事项‌

  • inline只是建议,编译器可能拒绝复杂函数的内联请求;
  • 调试版本建议禁用内联以便调试;
  • 头文件中实现的内联函数需加static避免多重定义;

【初级C++开发工程师基础进阶课程-夯实C+基础核心内容】

http://www.xdnf.cn/news/16966.html

相关文章:

  • Shell脚本-变量如何定义
  • 什么是DOM和BOM?
  • 搜索引擎评估革命:用户行为模型如何颠覆传统指标?
  • 数据结构1-概要、单向链表
  • [网安工具] Web 漏洞扫描工具 —— AWVS · 使用手册
  • 【C语言】内存函数与数据在内存中的存储
  • python -m build打包成为tar.gz或者whl
  • Qemu-NUC980(二):时钟clock代码添加
  • Redis数据库存储键值对的底层原理
  • SpringBoot相关注解
  • #Linux内存管理#缺页中断处理的核心函数是do_page_fault()的工作原理
  • Vulnhub ELECTRICAL靶机复现(附提权)
  • RPG增容2.尝试使用MMC根据游戏难度自定义更改怪物属性(三)
  • (LeetCode 面试经典 150 题) 138. 随机链表的复制 (哈希表)
  • Kotlin单例模式懒汉模式:LazyThreadSafetyMode.SYNCHRONIZED(2)
  • 深度学习(鱼书)day09--与学习相关的技巧(前三节)
  • P10816 [EC Final 2020] Namomo Subsequence|普及+
  • 机器学习实战:KNN算法全解析 - 从原理到创新应用
  • 【LeetCode 热题 100】(三)滑动窗口
  • Windows下定位Mingw编译的Qt程序崩溃堆栈
  • Python编程基础与实践:Python模块与包入门实践
  • 滚珠花键在汽车制造中有哪些高要求?
  • 什么叫湖仓一体
  • 存储过程的介绍、基本语法、delimiter的使用
  • Effective C++ 条款18:让接口容易被正确使用,不易被误用
  • Qwen3 Embedding:新一代文本表征与排序模型
  • [硬件电路-123]:模拟电路 - 信号处理电路 - 常见的高速运放芯片、典型电路、电路实施注意事项
  • 高效游戏状态管理:使用双模式位运算与数学运算
  • 网络基础实操篇-05-路由基础-最佳实践
  • WinForm之NumericUpDown控件