C语言:编译和链接

1. 翻译环境和运行环境

  1. 翻译环境:预编译+编译+汇编+链接
1. 翻译环境和运行环境

在标准 C(ANSI C)中,程序处理分为两个独立环境:

1.翻译环境 :将.c源代码,转换为二进制的可执行机器指令(编译 + 链接阶段)。

2.运行环境 :执行可执行程序,输出运行结果。

**整体流程:**多个.c源文件 → 翻译环境 → 可执行程序 → 运行环境 → 输出结果

2.翻译环境

翻译环境是由编译和链接 两个大的过程组成的,而编译 又可以分解成:预处理(有些书也叫预编
译)、编译、汇编三个过程。

1编译阶段

多个.c文件单独编译,每个文件生成目标文件

Windows 系统 :后缀为.obj

Linux 系统 :后缀为.o

**工具:**编译器(Windows 常用cl.exe,Linux 常用gcc)

2链接阶段

参与文件: 所有编译生成的目标文件 + 链接库(系统运行时库、第三方库)

工具: 链接器(Windows 常用link.exe)

最终产物:可执行程序(Windows 为.exe,Linux 为无后缀可执行文件)

2.1预处理(预编译****)

核心作用是处理源文件 / 头文件的预编译指令,生成后缀为 .i 的纯 C 代码文件。

GCC 实操命令

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

主要处理规则

1.宏处理 :删除#define,完全展开所有宏定义;

2.条件编译 :处理#if #ifdef #elif #else #endif;

3.头文件嵌入 :递归展开#include,把头文件内容直接插入源码;

4.清理注释 :删除所有单行 / 多行注释;

5.调试标记:添加行号、文件名标识,用于后续调试;

6.保留指令 :保留#pragma编译器指令。

!!! 排查技巧:宏定义、头文件包含异常时,可直接查看.i文件定位问题。

2.2编译

核心作用是对预处理后的.i文件,依次做词法分析→语法分析→语义分析→代码优化,生成汇编代码文件(.s)。

GCC 实操命令

cpp 复制代码
gcc -S test.i -o test.s
2.2.1 词法分析

原理: 扫描器将代码字符切割为记号(关键字、标识符、字面量、运算符等);

**示例:**代码 arrayindex = (index+4)*(2+6);经过词法分析后,会被拆分为16 个独立记号,完成字符到代码单元的转换。


后续编译流程

词法分析后还会执行:

语法分析 :构建语法树,检查语法格式是否合法;

语义分析 :检查类型匹配、作用域、表达式合法性;

代码优化:简化冗余计算(示例中2+6会直接优化为8)。

2.3汇编

核心作用是将编译生成的汇编代码(.s),翻译为二进制机器指令,生成目标文件。

特点 :逐条翻译、几乎不做优化,一条汇编语句对应一条机器指令。

文件后缀:Linux 为 .o,Windows 为 .obj

GCC 实操命令

cpp 复制代码
gcc -c test.s -o test.o
2.4链接

核心作用是将多个目标文件 + 系统库文件整合,解决多文件 / 多模块调用问题,最终生成可执行程序。
三大核心步骤

1.地址和空间分配: 统一规划所有代码、数据的内存布局

2.符号决议: 匹配函数、全局变量的声明与定义

**3.重定位:**修正跨模块调用的地址,补全真实内存地址

2.4.1实例解析(test.c + add.c)
cpp 复制代码
#include <stdio.h>
//test.c
//声明外部函数
extern int Add(int x, int y);
//声明外部的全局变量
extern int g_val;
int main()
{
    int a = 10;
    int b = 20;
    int sum = Add(a, b);
    printf("%d\n", sum);
    return 0;
}


add.c
int g_val = 2022;
int Add(int x, int y)
{
return x+y;
}

test.c 用 extern 声明外部函数 Add、全局变量 g_val,但编译时不知道真实地址;

add.c 定义 Add 函数和 g_val 全局变量;

两个文件分别编译生成 test.o、add.o;

链接器找到 Add、g_val 真实地址,修正 test.o 中的调用指令,该过程即重定位。

2.5运行环境

一.程序载入内存

操作系统环境(Windows/Linux):由操作系统自动完成,操作系统从磁盘读取可执行文件,分配内存空间,将程序加载到内存。裸机 / 独立环境(单片机、嵌入式):无操作系统,需手动载入,或直接将编译后的可执行代码烧录到只读存储器(ROM/Flash)中。

二.启动执行,调用main函数

程序加载完成后,系统 / 硬件初始化完成,自动调用main()函数,main是 C 程序的唯一入口。

三.代码执行,内存使用

程序运行时主要用到两类内存:

1.运行时栈(Stack)

用于存储局部变量、函数调用返回地址

函数调用时自动分配,函数结束后自动释放,生命周期随函数。

2.静态内存(static)

存储static修饰的静态变量、全局变量

程序整个运行期间都保留值,不会随函数结束释放

2.6程序终止

1.正常终止: main函数执行完毕返回(return 0)。

**2.意外终止:**程序崩溃、强制关闭、异常报错等。

相关推荐
会编程的土豆1 小时前
功能详解 01 · 用户注册:从表单到数据库一行
开发语言·数据库·后端·mysql·golang
Ivanqhz1 小时前
Rust collect() 浅析
开发语言·后端·rust
Wang's Blog2 小时前
Go-Zero项目开发33: IM实时通信前后端对接与微服务基础设施实践
开发语言·微服务·golang·go-zero
SelectDB技术团队2 小时前
丰巢日志平台 ELK 替代:Apache Doris / SelectDB 的技术能力与实践
开发语言·python
BetterFlow_CFD2 小时前
COMSOL声学仿真基础知识(二)
开发语言·算法·matlab
麻瓜老宋2 小时前
AI开发C语言应用按步走,表达式计算器calc的第十九步,注释、表达式分隔符、long double 精度
c语言·开发语言·atomcode
崖边看雾2 小时前
Python学习——函数
开发语言·windows·python·学习·pycharm
宸津-代码粉碎机2 小时前
Jar热部署进阶实战|修复原生方案OOM与类冲突问题,生产级无BUG优化方案
java·大数据·服务器·开发语言·前端·人工智能·python
dok122 小时前
zynq qt 交叉编译
开发语言·qt