C++的编译和链接过程是怎样的?C++程序从源码到可执行文件详解【底层原理】
发布时间 - 2026-01-23 00:00:00 点击率:次C++程序从.cpp到可执行文件需经历预处理、编译、汇编、链接四阶段:预处理展开宏与头文件生成.i文件;编译生成汇编.s文件;汇编生成目标.o文件;链接合并符号并重定位生成可执行文件。
一个C++程序从 .cpp 文件变成可直接运行的 ./a.out,要经历四个关键阶段:预处理 → 编译 → 汇编 → 链接。这不是简单的“一键构建”,而是分步转化、层层抽象的过程,每一步都解决不同层次的问题。
预处理(Preprocessing):处理 #include、#define 和条件编译
编译器调用预处理器(如 cpp),对源文件做纯文本替换和展开:
- 把所有
#include或#include "xxx.h"替换成对应头文件的实际内容(递归展开) - 展开所有
#define宏定义(包括函数式宏),删除注释,处理#ifdef/#ifndef等条件编译指令 - 生成一个“.i”文件(如
main.i),里面全是展开后的 C++ 代码,没有宏、没有头文件名、也没有注释
你可以用 g++ -E main.cpp -o main.i 手动触发这一步,打开 main.i 就能看到上千行“膨胀”后的代码——这就是后续所有工作的真正输入。
编译(Compilation):把高级代码翻译成汇编指令
编译器(如 g++ 的前端)分析 .i 文件的语法、语义,做类型检查、模板实例化、内联展开、优化(如 -O2),最后生|成人|类可读的汇编代码(.s 文件):
- 每个函数被翻译成一段带标签的汇编指令(如
_Z3addii是int add(int, int)的 mangled 名) - 变量分配在栈或寄存器中,类对象布局被确定(虚表指针位置、成员偏移等)
- 未定义的函数调用(如
printf)保留为符号引用,不关心具体地址
命令示例:g++ -S main.i -o main.s。此时还不能执行,因为汇编指令里写的都是符号名,不是内存地址。
汇编(Assembly):把汇编代码转成机器码(目标文件)
汇编器(如 as)把 .s 文件逐行翻译成二进制机器指令,打包成可重定位的目标文件(.o 文件):
- 生成的
.o文件包
含:机器码段(
.text)、已初始化数据(.data)、未初始化数据(.bss)、符号表(含全局函数/变量名及其大小、是否已定义)、重定位表(记录哪些地址需后期修正) - 所有外部符号(如
std::cout、malloc)仍保持“占位”,地址留空 -
.o文件还不是完整程序,不能直接运行(缺少入口、无动态链接信息、符号未解析)
命令示例:g++ -c main.s -o main.o 或直接 g++ -c main.cpp 跳过前两步。
链接(Linking):合并多个 .o,解析符号,生成最终可执行文件
链接器(如 ld)是“拼图大师”,它把多个 .o 文件 + 静态库(.a)+ 动态库(.so/.dll)组合起来:
- 符号解析:把每个
call _Z3addii找到对应.text段里的实际地址;把extern int x绑定到某个.o中定义的x - 重定位:根据最终内存布局,把所有跳转、取址指令中的地址填上真实值(比如把
mov rax, QWORD PTR x[rip]中的偏移算准) - 生成可执行格式(如 ELF):添加程序头(PHDR)、段信息(.text/.data/.dynamic)、动态符号表、解释器路径(/lib64/ld-linux-x86-64.so.2)、入口点(_start)
命令示例:g++ main.o utils.o -o program。若用到标准库,链接器会自动拉入 libc.a 或插入动态链接信息。
基本上就这些。预处理管文本、编译管逻辑、汇编管指令、链接管整合——四步环环相扣,缺一不可。理解它们,才能看懂 “undefined reference”、”multiple definition”、”segmentation fault at startup” 这些底层报错到底发生在哪一层。
# linux
# word
# 前端
# 处理器
# 栈
# ai
# c++
# 标准库
# define
# include
# printf
# extern
# 预处理器
# 递归
# int
# 指针
# undefined
# 对象
# 翻译成
# 多个
# 可执行文件
# 都是
# 头文件
# 就能
# 这就是
# 环环相扣
# 可以用
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251811 】
【
AI营销90571 】
相关推荐:
香港服务器网站推广:SEO优化与外贸独立站搭建策略
免费的流程图制作网站有哪些,2025年教师初级职称申报网上流程?
如何在宝塔面板中修改默认建站目录?
Laravel请求验证怎么写_Laravel Validator自定义表单验证规则教程
Laravel如何处理CORS跨域问题_Laravel项目CORS配置与解决方案
如何彻底删除建站之星生成的Banner?
laravel怎么配置和使用PHP-FPM来优化性能_laravel PHP-FPM配置与性能优化方法
Laravel如何实现API速率限制?(Rate Limiting教程)
网页制作模板网站推荐,网页设计海报之类的素材哪里好?
C#如何调用原生C++ COM对象详解
zabbix利用python脚本发送报警邮件的方法
nodejs redis 发布订阅机制封装实现方法及实例代码
Laravel的辅助函数有哪些_Laravel常用Helpers函数提高开发效率
利用vue写todolist单页应用
小米17系列还有一款新机?主打6.9英寸大直屏和旗舰级影像
Laravel Eloquent访问器与修改器是什么_Laravel Accessors & Mutators数据处理技巧
javascript和jQuery中的AJAX技术详解【包含AJAX各种跨域技术】
canvas 画布在主流浏览器中的尺寸限制详细介绍
Laravel怎么创建自己的包(Package)_Laravel扩展包开发入门到发布
Laravel如何使用Gate和Policy进行权限控制_Laravel权限判定与策略规则配置
如何在企业微信快速生成手机电脑官网?
如何快速上传自定义模板至建站之星?
php嵌入式断网后怎么恢复_php检测网络重连并恢复硬件控制【操作】
Bootstrap整体框架之JavaScript插件架构
Win11摄像头无法使用怎么办_Win11相机隐私权限开启教程【详解】
js实现点击每个li节点,都弹出其文本值及修改
Laravel如何集成Inertia.js与Vue/React?(安装配置)
高性能网站服务器配置指南:安全稳定与高效建站核心方案
如何用5美元大硬盘VPS安全高效搭建个人网站?
家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?
如何快速配置高效服务器建站软件?
laravel怎么为应用开启和关闭维护模式_laravel应用维护模式开启与关闭方法
Laravel怎么生成URL_Laravel路由命名与URL生成函数详解
Laravel怎么清理缓存_Laravel optimize clear命令详解
想要更高端的建设网站,这些原则一定要坚持!
清除minerd进程的简单方法
如何快速生成专业多端适配建站电话?
如何确保FTP站点访问权限与数据传输安全?
详解Android——蓝牙技术 带你实现终端间数据传输
UC浏览器如何切换小说阅读源_UC浏览器阅读源切换【方法】
最好的网站制作公司,网购哪个网站口碑最好,推荐几个?谢谢?
HTML5打空格有哪些误区_新手常犯的空格使用错误【技巧】
详解Huffman编码算法之Java实现
Laravel怎么实现搜索高亮功能_Laravel结合Scout与Algolia全文检索【实战】
如何使用 jQuery 正确渲染 Instagram 风格的标签列表
如何正确下载安装西数主机建站助手?
详解MySQL数据库的安装与密码配置
个人摄影网站制作流程,摄影爱好者都去什么网站?
js实现获取鼠标当前的位置
什么是JavaScript解构赋值_解构赋值有哪些实用技巧
上一篇:notepad怎么运行代码
下一篇:notepad怎么模糊替换
上一篇:notepad怎么运行代码
下一篇:notepad怎么模糊替换


