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

【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.dtcms.com/a/313188.html

相关文章:

  • json-server 快速搭建本地 Mock 数据服务
  • Day23--回溯--39. 组合总和,40. 组合总和 II,131. 分割回文串
  • Android 之 MVC架构
  • 线段树学习笔记 - 摩尔投票问题
  • I2C基础
  • mybatis-plus从入门到入土(四):持久层接口之BaseMapper和选装件
  • PHP现代化全栈开发:前后端分离与API架构实践
  • uni-app学习笔记01-项目初始化及相关文件
  • Go语言常量
  • 11.消息队列
  • 计算机视觉CS231n学习(2)
  • 从马武寨穿越关山
  • ICCV 2025 | EPD-Solver:西湖大学发布并行加速扩散采样算法
  • p5.js 用 beginGeometry () 和 endGeometry () 打造自定义 3D 模型
  • 控制建模matlab练习06:比例积分控制-②PI控制器
  • 达梦数据库联机备份和脱机备份的区别
  • Centos7 安装Python3.11
  • 【Linux系统编程】进程信号
  • leecode2958 最多K个重复元素的最长子数组
  • 解决飞书文档中PDF文档禁止下载的问题
  • 提升工作效率的利器:Qwen3 大语言模型
  • Python 程序设计讲义(60):Python 的函数——递归函数
  • 出现OOM怎么排查
  • 研报复现|史蒂夫·路佛价值选股法则
  • linux ollama模型缓存位置变更
  • 音视频学习(四十九):音频有损压缩
  • 机器学习之决策树(二)
  • 解决PyCharm的Terminal终端conda环境默认为base的问题
  • 【硬件-笔试面试题】硬件/电子工程师,笔试面试题-57,(知识点:电感的选型,电感参数,电感量,饱和电流,直流电阻,自谐振频率)
  • 可视化AI应用构建工具(Dyad)