C语言的编译过程详解
- 当我们编译C程序时会发生什么?
- 编译过程中的组件有哪些,编译执行过程是什么样的?
-
什么是编译
C语言的编译过程就是把我们可以理解的高级语言代码转换为计算机可以理解的机器代码的过程,其实就是一个翻译的过程。
源代码和可执行机器代码
程序编译是将源代码转换为可执行代码的过程,通常包括以下几个主要步骤:
-
预处理(Preprocessing): 在这个阶段,预处理器会处理源代码文件,执行一些预处理指令。常见的预处理指令包括
#include(用于包含头文件)、#define(用于定义宏)、#ifdef和#ifndef(用于条件编译)等。预处理器的输出通常是一个经过预处理的源代码文件。 -
编译(Compilation): 编译器接收预处理后的源代码并将其转换为汇编代码。汇编代码是一种低级的代码,与特定的计算机体系结构相关。编译器会执行语法分析、语义分析和代码生成等操作。如果在这个阶段发现语法错误或其他编译错误,编译过程会中止,并输出错误消息。
-
汇编(Assembly): 汇编器接收编译器生成的汇编代码,并将其转换为机器代码或可重定位目标代码。汇编过程将汇编指令转换为二进制形式,同时解析符号引用,生成可执行的机器代码或可链接的目标文件。
-
链接(Linking): 如果程序由多个源代码文件组成,编译后会生成多个目标文件。链接器接受这些目标文件以及所需的库文件,并将它们组合成一个可执行文件。链接过程涉及解析符号引用,将不同模块之间的引用关系解决,并生成最终的可执行文件。这也包括动态链接(在运行时加载共享库)或静态链接(在编译时将库链接到可执行文件)。
-
优化(Optimization)(可选): 一些编译器在生成目标代码之前会执行优化步骤,以提高程序的性能或减小可执行文件的大小。优化可以包括常量折叠、循环展开、内联函数、无用代码删除等操作。
-
生成可执行文件(Executable Generation): 最终的可执行文件包含了机器代码,它是计算机可以直接执行的二进制文件。这个文件可以通过操作系统加载到内存中,并执行。
总之,程序编译的过程包括预处理、编译、汇编、链接和可选的优化步骤,最终生成可执行文件。不同的编程语言和编译器可能在这个过程中有些许不同,但这个基本流程适用于大多数编程环境.
详细分析
C 语言的编译过程主要包括四个步骤:
- 预处理
- 编译
- 汇编
- 连接
下面这张图就是C程序编译的完整过程

接下我们看看编译过程不同阶段都在做什么。
1.预处理
编译过程的第一步预就是预处理,与处理结束后会产生一个后缀为(.i)的临时文件,这一步由预处理器完成。预处理器主要完成以下任务。
- 删除所有的注释
- 宏扩展
- 文件包含
预处理器会在编译过程中删除所有注释,因为注释不属于程序代码,它们对程序的运行没有特别作用。
宏是使用 #define 指令定义的一些常量值或表达式。宏调用会导致宏扩展。预处理器创建一个中间文件,其中一些预先编写的汇编级指令替换定义的表达式或常量(基本上是匹配的标记)。为了区分原始指令和宏扩展产生的程序集指令,在每个宏展开语句中添加了一个“+”号。
文件包含
C语言中的文件包含是在预处理期间将另一个包含一些预写代码的文件添加到我们的C程序中。它是使用#include指令完成的。在预处理期间包含文件会导致在源代码中添加文件名的全部内容,从而替换#include<文件名>指令,从而创建新的中间文件。
2.编译
C 中的编译阶段使用内置编译器软件将 (.i) 临时文件转换为具有汇编级指令(低级代码)的汇编文件 (.s)。为了提高程序的性能,编译器将中间文件转换为程序集文件。
汇编代码是一种简单的英文语言,用于编写低级指令(在微控制器程序中,我们使用汇编语言)。整个程序代码由编译器软件一次性解析(语法分析),并通过终端窗口告诉我们源代码中存在的任何语法错误或警告。
下图显示了编译阶段如何工作的示例。
3.组装
使用汇编程序将程序集级代码(.s 文件)转换为机器可理解的代码(二进制/十六进制形式)。汇编程序是一个预先编写的程序,它将汇编代码转换为机器代码。它从程序集代码文件中获取基本指令,并将其转换为特定于计算机类型(称为目标代码)的二进制/十六进制代码。
生成的文件与程序集文件同名,在 DOS 中称为扩展名为 .obj 的对象文件,在 UNIX 操作系统中扩展名为 .o。
下图显示了组装阶段如何工作的示例。程序集文件 hello.s 将转换为具有相同名称但扩展名不同的对象文件 hello.o。
4. 链接
链接是将库文件包含在我们的程序中的过程。库文件是一些预定义的文件,其中包含机器语言中的函数定义,这些文件的扩展名为.lib。一些未知语句写入我们的操作系统无法理解的对象 (.o/.obj) 文件中。你可以把它理解为一本书,里面有一些你不知道的单词,你会用字典来找到这些单词的含义。同样,我们使用库文件来为对象文件中的一些未知语句赋予意义。链接过程会生成一个可执行文件,其扩展名为 .exe 在 DOS 中为 .out,在 UNIX 操作系统中为 .out。
下图显示了链接阶段如何工作的示例,我们有一个具有机器级代码的对象文件,它通过链接器传递,链接器将库文件与对象文件链接以生成可执行文件。
举例
接下来,我们通过一个例子详细看看C编译过程中涉及的所有步骤。第一步先写一个简单的C程序并保存为hello.c
// Simple Hello World program in C
#include<stdio.h>
int main()
{// printf() is a output function which prints// the passed string in the output consoleprintf("Hello World!");return 0;
}
接着我们执行编译命令对hello.c进行编译:
gcc -save-temps hello.c -o compilation
-save-temps 选项会保留所有编译过程中产生的中间文件,总共会生成四个文件。
- hello.i 预处理器产生的文件
- hello.s 编译器编译后产生的文件
- hello.o 汇编程序翻译后的目标文件
- hello.exe 可执行文件(Linux系统会产生hello.out文件)
首先,我们的C程序的预处理开始,注释从程序中删除,因为该程序中没有宏指令,因此宏扩展不会发生,我们还包含了一个stdio.h头文件,并且在预处理期间,标准输入/输出函数(如printf(),scanf()等)的声明被添加到我们的C程序中。
打开预处理阶段产生的hello.i 文件就可以看到类似下面这样的代码。
# 1 "hello.c"
# 1 ""
# 1 ""
# 1 "hello.c"# 1 "C:/Program Files (x86)/CodeBlocks/MinGW/include/stdio.h" 1 3
# 293 "C:/Program Files (x86)/CodeBlocks/MinGW/include/stdio.h" 3int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) fprintf (FILE*, const char*, ...);int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) printf (const char*, ...);int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) sprintf (char*, const char*, ...);int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) scanf (const char*, ...);int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) sscanf (const char*, const char*, ...);...
...
...int __attribute__((__cdecl__)) __attribute__ ((__nothrow__)) putw (int, FILE*);
# 3 "hello.c" 2int main()
{printf("Hello World!");return 0;
}
从上面的代码中可以看到,预编译过后,所有的注释没有了,#include <stdio.h>也被它的头文件内容代替了。
接下来就是编译阶段,编译器接收到hello.i 文件将它转化为汇编代码hello.s文件。这过程中发生了以下几件事:
- 编译器检查语法错误
- 将源代码翻译中间代码,例如汇编代码
- 对代码进行优化
编译结束后产生的hello.s 文件长这个样子:
.file "hello.c".def ___main; .scl 2; .type 32; .endef.section .rdata,"dr"
LC0:.ascii "Hello World!\0".text.globl _main.def _main; .scl 2; .type 32; .endef
_main:
LFB12:.cfi_startprocpushl %ebp.cfi_def_cfa_offset 8.cfi_offset 5, -8movl %esp, %ebp.cfi_def_cfa_register 5andl $-16, %espsubl $16, %espcall ___mainmovl $LC0, (%esp)call _printfmovl $0, %eaxleave.cfi_restore 5.cfi_def_cfa 4, 4ret.cfi_endproc
LFE12:.ident "GCC: (MinGW.org GCC-6.3.0-1) 6.3.0".def _printf; .scl 2; .type 32; .endef
接下来,汇编程序把hello.s 文件转换为二进制代码,并在Windows环境中生成对象文件 hello.obj,在 Linux系统中生成 hello.o文件。
接着,链接器使用库文件将所需的定义添加到对象文件中,并在Windows环境中生成一个可执行文件 hello.exe,在 Linux操作系统中生成 hello.out文件。
- 当我们运行 hello.exe/hello.out 时,我们会在屏幕上 输出 Hello World!。
程序流程图
让我们看一下C语言编译过程中程序的流程图:

结论
- C中的编译过程也称为将人类可理解代码(C程序)转换为机器可理解代码(二进制代码)的过程。
- C语言的编译过程包括四个步骤:预处理、编译、汇编和链接。
- 预处理器执行删除注释、宏扩展、文件包含。这些命令在编译过程的第一步执行。
- 编译器可以提高程序的性能,并将中间文件转换为汇编文件。
- 汇编程序有助于将汇编文件转换为包含机器代码的对象文件。
- 链接器用于将库文件与对象文件链接。这是编译中生成可执行文件的最后一步。
参考网址:
C程序的编译_c编译_。菀枯。的博客-CSDN博客
C语言的编译过程详解 - 知乎
相关文章:
C语言的编译过程详解
当我们编译C程序时会发生什么?编译过程中的组件有哪些,编译执行过程是什么样的? 什么是编译 C语言的编译过程就是把我们可以理解的高级语言代码转换为计算机可以理解的机器代码的过程,其实就是一个翻译的过程。 …...
无人机航测没信号?北斗卫星来解决
无人机航测是利用无人机进行地理信息的采集和处理的航测方式。相比传统的航测手段,无人机航测具备更高的灵活性、更低的成本和更广阔的适应性。无人机航测可以应用于土地测绘、农业植保、城市规划、自然资源调查等多个领域,极大地提高了测绘的效率和准确…...
Vue 03 数据绑定
Vue中有2种数据绑定的方式: 1.单向绑定(v-bind): 数据只能从data流向页面。 2.双向绑定(v-model): 数据不仅能从data流向页面,还可以从页面流向data。 备注: 1.双向绑定一般都应用在表单类元素上(如&am…...
#循循渐进学51单片机#步进电机与蜂鸣器#not.8
1、能够理解清楚单片机IO口的结构。 2)t1相当于PnP三级管,t2相当于npn三极管 3) 强推挽io具有较强的驱动能力,电流输出能力很强。 2、能够看懂上下拉电阻的电路应用,并且熟练使用上下拉电阻。 3、理解28BYJ-48减速步进电机的工作…...
计算存储是不是智算时代的杀手锏?
想象一下,在一个繁忙的数据中心里,有一家大型互联网公司叫做“数据中心的故事”。这家公司一直在使用传统的CPU架构来处理海量数据。但是随着数据量的不断增长,CPU架构遇到了很多问题和瓶颈,这让“数据中心的故事”感到非常苦恼。…...
西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(二)
西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(二) 上一次和大家分享了组态相关的重要内容,具体可以参考以下链接中的内容: 西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(一) 本次继续和大家分享关于安全PLC基础编程的相关内容: 如下图所示,在左侧的…...
【Spring Boot】Spring Boot中的简单查询
前面介绍了在Spring Boot项目中集成JPA框架,实现数据的增、删、改、查等功能。Spring Data JPA的使用非常简单,只需继承JpaRepository即可实现完整的数据操作方法,无须任何数据访问层和SQL语句。JPA除了这些功能和优势之外,还有非…...
Transformer 01(自注意机制Self-attention)
一、Self-attention [台大李宏毅] 1.1 向量序列的输入 一个序列作为输入: 多个向量输入举例: 一个句子: 声音信号: 图: 1.2 输出 二、Sequence labeling 输入与输出一样多:Sequence labeling 窗口开的…...
交流共享,共筑智算底座丨九州未来受邀出席英特尔线下沙龙
随着AI技术的升级迭代、生成式AI模型智能化水平的持续提升,AIGC加速向多种场景渗透,AIGC迎来应用爆发期,有望实现且跨越更多领域的融合,形成新的应用场景和解决方案,持续推动数字技术的创新与应用,助力各行…...
【EI会议信息】第五届土木建筑与城市工程国际学术会议(ICCAUE 2023)
第五届土木建筑与城市工程国际学术会议(ICCAUE 2023) 2023 5th International Conference on Civil Architecture and Urban Engineering (ICCAUE 2023) 第五届土木建筑与城市工程国际学术会议(ICCAUE 2023)由天津大学主办&…...
上海亚商投顾:沪指震荡反弹 汽车产业链全天强势
上海亚商投顾前言:无惧大盘涨跌,解密龙虎榜资金,跟踪一线游资和机构资金动向,识别短期热点和强势个股。 一.市场情绪 大小指数昨日集体反弹,沪指3100点失而复得,创业板指一度涨超1.5%,随后涨幅…...
【Python深度学习】深度学习入门介绍
引言 深度学习是人工智能领域中最受关注和研究的子领域之一,它在计算机视觉、自然语言处理、语音识别、推荐系统等各个领域都有广泛的应用。本文将详细介绍深度学习的发展历史、不同类型、应用领域以及未来发展前景。 1、深度学习的发展历史 深度学习的起源可以追溯…...
【Linux系统编程】进程概念与基本创建
文章目录 1. 进程的概念2. 进程描述—PCB3. task_struct—PCB的一种4. task_ struct内容分类5. 查看进程 这篇文章我们来学习下一个概念——进程 1. 进程的概念 那什么是进程呢,我们该如何理解它呢? 如果我们打开电脑的任务管理: 我们看到这…...
webpack:详解CopyWebpackPlugin,复制的同时修改文件内容
摘要 CopyWebpackPlugin 是一个强大的 Webpack 插件,用于将文件从源目录复制到构建目录。在本文中,我们将探讨 CopyWebpackPlugin 的一些常用 API,并提供示例代码。 在构建 Web 应用程序时,通常需要将一些静态文件(如…...
Twin-Builder—系统级多物理域数字孪生平台
Twin Builder是ANSYS公司系统仿真业务的核心产品,是一款跨学科多领域系统仿真软件和数字孪生平台。能够实现复杂系统的建模、仿真和验证,基于IIoT物联网平台对数字孪生体进行集成、部署与运行,在完成复杂系统功能、性能的验证和优化的同时&am…...
用selenium和xpath定位元素并获取属性值以及str字符型转json型
页面html如图所示: 要使用xpath定位这个div元素,并且获取其属性data-config的内容值。 from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.chrome.options import Optionshost127.0.0.1 port10808 …...
基于Java的电影院管理系统设计与实现
前言 💗博主介绍:✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 👇🏻…...
Linux Static Key原理与应用
文章目录 背景1. static-key的使用方法1.1. static-key定义1.2 初始化1.3 条件判断1.4 修改判断条件 2、示例代码参考链接 背景 内核中有很多判断条件在正常情况下的结果都是固定的,除非极其罕见的场景才会改变,通常单个的这种判断的代价很低可以忽略&a…...
linux ssh 禁止指定用户通过ssh登录
Linux 禁止用户或 IP通过 SSH 登录 限制用户 SSH 登录 1.只允许指定用户进行登录(白名单): 在 /etc/ssh/sshd_config 配置文件中设置 AllowUsers 选项,(配置完成需要重启 SSHD 服务)格式如下:…...
快速学习Netty
Netty框架探索:助力高效网络编程 一、Netty是个啥?二、“Hello World”服务器端实现(Server)客户端实现(Client)思考🤔 三、Netty的核心组件EventLoopChannelChannelPipelineChannelHandlerByte…...
【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型
摘要 拍照搜题系统采用“三层管道(多模态 OCR → 语义检索 → 答案渲染)、两级检索(倒排 BM25 向量 HNSW)并以大语言模型兜底”的整体框架: 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后,分别用…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
MongoDB学习和应用(高效的非关系型数据库)
一丶 MongoDB简介 对于社交类软件的功能,我们需要对它的功能特点进行分析: 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具: mysql:关系型数据库&am…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Spring AI 入门:Java 开发者的生成式 AI 实践之路
一、Spring AI 简介 在人工智能技术快速迭代的今天,Spring AI 作为 Spring 生态系统的新生力量,正在成为 Java 开发者拥抱生成式 AI 的最佳选择。该框架通过模块化设计实现了与主流 AI 服务(如 OpenAI、Anthropic)的无缝对接&…...
Unit 1 深度强化学习简介
Deep RL Course ——Unit 1 Introduction 从理论和实践层面深入学习深度强化学习。学会使用知名的深度强化学习库,例如 Stable Baselines3、RL Baselines3 Zoo、Sample Factory 和 CleanRL。在独特的环境中训练智能体,比如 SnowballFight、Huggy the Do…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
GitHub 趋势日报 (2025年06月06日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 590 cognee 551 onlook 399 project-based-learning 348 build-your-own-x 320 ne…...
