0

0

C++的编译和链接过程是怎样的?C++程序从源码到可执行文件详解【底层原理】

穿越時空

穿越時空

发布时间:2026-01-23 13:52:02

|

973人浏览过

|

来源于php中文网

原创

C++程序从.cpp到可执行文件需经历预处理、编译、汇编、链接四阶段:预处理展开宏与头文件生成.i文件;编译生成汇编.s文件;汇编生成目标.o文件;链接合并符号并重定位生成可执行文件。

c++的编译和链接过程是怎样的?c++程序从源码到可执行文件详解【底层原理】

一个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 文件):

立即学习C++免费学习笔记(深入)”;

  • 每个函数被翻译成一段带标签的汇编指令(如 _Z3addiiint add(int, int) 的 mangled 名)
  • 变量分配在或寄存器中,类对象布局被确定(虚表指针位置、成员偏移等)
  • 未定义的函数调用(如 printf)保留为符号引用,不关心具体地址

命令示例:g++ -S main.i -o main.s。此时还不能执行,因为汇编指令里写的都是符号名,不是内存地址。

通义千问
通义千问

阿里巴巴推出的全能AI助手

下载

汇编(Assembly):把汇编代码转成机器码(目标文件)

汇编器(如 as)把 .s 文件逐行翻译成二进制机器指令,打包成可重定位的目标文件(.o 文件):

  • 生成的 .o 文件包含:机器码段(.text)、已初始化数据(.data)、未初始化数据(.bss)、符号表(含全局函数/变量名及其大小、是否已定义)、重定位表(记录哪些地址需后期修正)
  • 所有外部符号(如 std::coutmalloc)仍保持“占位”,地址留空
  • .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” 这些底层报错到底发生在哪一层。

相关专题

更多
typedef和define区别
typedef和define区别

typedef和define区别在类型检查、作用范围、可读性、错误处理和内存占用等。本专题为大家提供typedef和define相关的文章、下载、课程内容,供大家免费下载体验。

108

2023.09.26

define的用法
define的用法

define用法:1、定义常量;2、定义函数宏:3、定义条件编译;4、定义多行宏。更多关于define的用法的内容,大家可以阅读本专题下的文章。

336

2023.10.11

printf用法大全
printf用法大全

php中文网为大家提供printf用法大全,以及其他printf函数的相关文章、相关下载资源以及各种相关课程,供大家免费下载体验。

73

2023.06.20

fprintf和printf的区别
fprintf和printf的区别

fprintf和printf的区别在于输出的目标不同,printf输出到标准输出流,而fprintf输出到指定的文件流。根据需要选择合适的函数来进行输出操作。更多关于fprintf和printf的相关文章详情请看本专题下面的文章。php中文网欢迎大家前来学习。

282

2023.11.28

string转int
string转int

在编程中,我们经常会遇到需要将字符串(str)转换为整数(int)的情况。这可能是因为我们需要对字符串进行数值计算,或者需要将用户输入的字符串转换为整数进行处理。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

358

2023.08.02

int占多少字节
int占多少字节

int占4个字节,意味着一个int变量可以存储范围在-2,147,483,648到2,147,483,647之间的整数值,在某些情况下也可能是2个字节或8个字节,int是一种常用的数据类型,用于表示整数,需要根据具体情况选择合适的数据类型,以确保程序的正确性和性能。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

542

2024.08.29

c++怎么把double转成int
c++怎么把double转成int

本专题整合了 c++ double相关教程,阅读专题下面的文章了解更多详细内容。

53

2025.08.29

C++中int的含义
C++中int的含义

本专题整合了C++中int相关内容,阅读专题下面的文章了解更多详细内容。

197

2025.08.29

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

0

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
PostgreSQL 教程
PostgreSQL 教程

共48课时 | 7.6万人学习

Git 教程
Git 教程

共21课时 | 2.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号