编译链接流程与底层细节

个人主页流年如夢

专栏《C语言》

因为要用到 gcc 编译环境,作者本人目前还不会🥹,相关截图没有,可以先大概了解一下,后面学习了会补充完整,请谅解🙏🙏🙏,感谢支持。

文章目录

Ladies and gentlemen,本篇文章讲的是 翻译环境、运行环境、预处理、编译、汇编、链接 全过程,是理解程序底层运行、解决多文件编译问题;全程高能,不容错过!!!

前言

我们写的.c源代码,无法直接被计算机执行,必须经过一系列翻译步骤,变成可执行程序。这个过程就是编译+链接 。理解编译与链接,能帮助大家搞懂头文件重复包含、宏展开、extern
作用、重定位、符号解析等
底层问题,写出更规范、更稳定的多文件项目

一.翻译环境

翻译环境就是把源代码转换成可执行程序(二进制)

其中有四步核心流程👉.c --> 预处理 --> .i --> 编译 --> .s --> 汇编 --> .o.obj --> 链接 --> .exe

更具体的流程图如图所示:

1.1预处理

功能
.i文件 --> 汇编代码.s

主要工作内容

  1. 展开#include头文件,把内容插入进来
  2. 展开#define宏定义,并删除#define
  3. 删除所有注释
  4. 处理条件编译#if #ifdef #endif
  5. 添加行号、文件名,保留#pragma

指令(在gcc)

c 复制代码
gcc -E test.c -o test.i

🧐分析-E只进行预处理,停止在预处理阶段;-o是输出到指定文件

1.2编译

功能

.i文件 --> 汇编代码.s

步骤

  1. 词法分析:拆分关键字、标识符、数字、符号
  2. 语法分析:生成语法树
  3. 语义分析:类型检查、匹配
  4. 优化:生成最优汇编代码

指令(在gcc)

c 复制代码
gcc -S test.i -o test.s

🧐分析-S只进行编译,生成汇编文件.s

1.3汇编

功能

把汇编代码.s --> 机器指令(二进制目标文件.o.obj

特点

  1. 不做优化
  2. 一条汇编指约等于一条机器指令

指令(在gcc)

c 复制代码
gcc -c test.s -o test.o

🧐分析-c只进行汇编,生成目标文件.o

1.4链接

功能

把多个.o.obj+库文件 --> 可执行文件.exe

主要工作内容

  1. 符号解析:找到函数、全局变量的地址
  2. 重定位:修正所有调用地址
  3. 地址与空间分配

举个例子

add.c文件

c 复制代码
int g_val = 2022;
int Add(int x, int y)
{
    return x + y;
}

test.c文件

c 复制代码
#include <stdio.h>

extern int Add(int x, int y);
extern int g_val;

int main()
{
    int sum = Add(10, 20);
    printf("%d\n", sum);
    printf("%d\n", g_val);
    
    return 0;
}

🧐分析
test.c单独编译生成test.oadd.c单独编译生成add.o

链接时:找到Add函数地址;找到g_val地址;修正调用指令 --> 重定位完成

二.运行环境

运行环境是执行已经生成好的可执行程序

运行步骤

先把可执行程序加载到内存

⬇️

然后从main函数开始执行

⬇️

接着使用栈存放局部变量、函数调用

⬇️

再使用静态区存放全局变量、static变量

⬇️

最后程序结束

🎯总结

  1. 翻译环境 :源代码 --> 可执行程序,四步流程:预处理(test.c) --> 编译(test.i) --> 汇编(test.s) --> 链接(test.o或.obj),最后到可执行程序(test.exe)
  2. 预处理:展开头文件、宏、删注释
  3. 编译:生成汇编代码
  4. 汇编:生成机器码目标文件
  5. 链接:多文件合并、符号解析、重定位
  6. 运行环境 :加载内存、执行main、使用栈与静态区

⚠️易错点

  1. 以为.c直接变.exe,不知道四步流程
  2. 混淆编译和链接的职责
  3. 不知道预处理会删除注释、展开头文件和宏
  4. 多文件中忘记extern声明,链接报错
  5. 目标文件.o.obj已是二进制,但不能直接运行
  6. 重定位是链接阶段完成,不是编译阶段

👀 关注 我们一路同行,从入门到大师,慢慢沉淀、稳步成长
❤️ 点赞 鼓励原创,让优质内容被更多人看见
⭐ 收藏 收好核心知识点与实战技巧,需要时随时查阅
💬 评论 分享你的疑问或踩坑经历,一起交流避坑、共同进步

相关推荐
Navigator_Z1 小时前
LeetCode //C - 1026. Maximum Difference Between Node and Ancestor
c语言·算法·leetcode
YSF2017_32 小时前
C语言15-makefile(2)——makefile的自定义变量及两个函数
c语言·开发语言
Lazionr3 小时前
数据结构入门:栈实现全解析
c语言·数据结构
光子物联单片机3 小时前
STM32传感器模块编程实践(二十)ESP8266实现MQTT连接OneNET上传温湿度数据
c语言·stm32·单片机·嵌入式硬件·mqtt
Lazionr3 小时前
数据结构队列详解:从概念到代码实现
c语言·数据结构
流年如夢3 小时前
编译前奏:预处理全面梳理
c语言
freshman_y15 小时前
一篇介绍C语言中二级指针和二维数组的文章
c语言·开发语言
weixin_4139206115 小时前
LVGL仪表显示项目
c语言
小柯博客17 小时前
STM32MP2安全启动技术深度解析
c语言·c++·stm32·嵌入式硬件·安全·开源·github