当前位置: 首页 > news >正文

C语言的编译过程详解

  • 当我们编译C程序时会发生什么?
  • 编译过程中的组件有哪些,编译执行过程是什么样的?
  • 什么是编译

    C语言的编译过程就是把我们可以理解的高级语言代码转换为计算机可以理解的机器代码的过程,其实就是一个翻译的过程。

                                                           源代码和可执行机器代码

程序编译是将源代码转换为可执行代码的过程,通常包括以下几个主要步骤:

  1. 预处理(Preprocessing): 在这个阶段,预处理器会处理源代码文件,执行一些预处理指令。常见的预处理指令包括#include(用于包含头文件)、#define(用于定义宏)、#ifdef#ifndef(用于条件编译)等。预处理器的输出通常是一个经过预处理的源代码文件。

  2. 编译(Compilation): 编译器接收预处理后的源代码并将其转换为汇编代码。汇编代码是一种低级的代码,与特定的计算机体系结构相关。编译器会执行语法分析、语义分析和代码生成等操作。如果在这个阶段发现语法错误或其他编译错误,编译过程会中止,并输出错误消息。

  3. 汇编(Assembly): 汇编器接收编译器生成的汇编代码,并将其转换为机器代码或可重定位目标代码。汇编过程将汇编指令转换为二进制形式,同时解析符号引用,生成可执行的机器代码或可链接的目标文件。

  4. 链接(Linking): 如果程序由多个源代码文件组成,编译后会生成多个目标文件。链接器接受这些目标文件以及所需的库文件,并将它们组合成一个可执行文件。链接过程涉及解析符号引用,将不同模块之间的引用关系解决,并生成最终的可执行文件。这也包括动态链接(在运行时加载共享库)或静态链接(在编译时将库链接到可执行文件)。

  5. 优化(Optimization)(可选): 一些编译器在生成目标代码之前会执行优化步骤,以提高程序的性能或减小可执行文件的大小。优化可以包括常量折叠、循环展开、内联函数、无用代码删除等操作。

  6. 生成可执行文件(Executable Generation): 最终的可执行文件包含了机器代码,它是计算机可以直接执行的二进制文件。这个文件可以通过操作系统加载到内存中,并执行。

总之,程序编译的过程包括预处理、编译、汇编、链接和可选的优化步骤,最终生成可执行文件。不同的编程语言和编译器可能在这个过程中有些许不同,但这个基本流程适用于大多数编程环境.

详细分析

C 语言的编译过程主要包括四个步骤:

  1. 预处理
  2. 编译
  3. 汇编
  4. 连接

下面这张图就是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程序时会发生什么&#xff1f;编译过程中的组件有哪些&#xff0c;编译执行过程是什么样的? 什么是编译 C语言的编译过程就是把我们可以理解的高级语言代码转换为计算机可以理解的机器代码的过程&#xff0c;其实就是一个翻译的过程。 …...

无人机航测没信号?北斗卫星来解决

无人机航测是利用无人机进行地理信息的采集和处理的航测方式。相比传统的航测手段&#xff0c;无人机航测具备更高的灵活性、更低的成本和更广阔的适应性。无人机航测可以应用于土地测绘、农业植保、城市规划、自然资源调查等多个领域&#xff0c;极大地提高了测绘的效率和准确…...

Vue 03 数据绑定

Vue中有2种数据绑定的方式&#xff1a; 1.单向绑定(v-bind)&#xff1a; 数据只能从data流向页面。 2.双向绑定(v-model)&#xff1a; 数据不仅能从data流向页面&#xff0c;还可以从页面流向data。 备注&#xff1a; 1.双向绑定一般都应用在表单类元素上&#xff08;如&am…...

#循循渐进学51单片机#步进电机与蜂鸣器#not.8

1、能够理解清楚单片机IO口的结构。 2)t1相当于PnP三级管&#xff0c;t2相当于npn三极管 3&#xff09; 强推挽io具有较强的驱动能力&#xff0c;电流输出能力很强。 2、能够看懂上下拉电阻的电路应用&#xff0c;并且熟练使用上下拉电阻。 3、理解28BYJ-48减速步进电机的工作…...

计算存储是不是智算时代的杀手锏?

想象一下&#xff0c;在一个繁忙的数据中心里&#xff0c;有一家大型互联网公司叫做“数据中心的故事”。这家公司一直在使用传统的CPU架构来处理海量数据。但是随着数据量的不断增长&#xff0c;CPU架构遇到了很多问题和瓶颈&#xff0c;这让“数据中心的故事”感到非常苦恼。…...

西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(二)

西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(二) 上一次和大家分享了组态相关的重要内容,具体可以参考以下链接中的内容: 西门子S7-1200F或1500F系列安全PLC的组态步骤和基础编程(一) 本次继续和大家分享关于安全PLC基础编程的相关内容: 如下图所示,在左侧的…...

【Spring Boot】Spring Boot中的简单查询

前面介绍了在Spring Boot项目中集成JPA框架&#xff0c;实现数据的增、删、改、查等功能。Spring Data JPA的使用非常简单&#xff0c;只需继承JpaRepository即可实现完整的数据操作方法&#xff0c;无须任何数据访问层和SQL语句。JPA除了这些功能和优势之外&#xff0c;还有非…...

Transformer 01(自注意机制Self-attention)

一、Self-attention [台大李宏毅] 1.1 向量序列的输入 一个序列作为输入&#xff1a; 多个向量输入举例&#xff1a; 一个句子&#xff1a; 声音信号&#xff1a; 图&#xff1a; 1.2 输出 二、Sequence labeling 输入与输出一样多&#xff1a;Sequence labeling 窗口开的…...

交流共享,共筑智算底座丨九州未来受邀出席英特尔线下沙龙

随着AI技术的升级迭代、生成式AI模型智能化水平的持续提升&#xff0c;AIGC加速向多种场景渗透&#xff0c;AIGC迎来应用爆发期&#xff0c;有望实现且跨越更多领域的融合&#xff0c;形成新的应用场景和解决方案&#xff0c;持续推动数字技术的创新与应用&#xff0c;助力各行…...

【EI会议信息】第五届土木建筑与城市工程国际学术会议(ICCAUE 2023)

第五届土木建筑与城市工程国际学术会议&#xff08;ICCAUE 2023&#xff09; 2023 5th International Conference on Civil Architecture and Urban Engineering (ICCAUE 2023) 第五届土木建筑与城市工程国际学术会议&#xff08;ICCAUE 2023&#xff09;由天津大学主办&…...

上海亚商投顾:沪指震荡反弹 汽车产业链全天强势

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一.市场情绪 大小指数昨日集体反弹&#xff0c;沪指3100点失而复得&#xff0c;创业板指一度涨超1.5%&#xff0c;随后涨幅…...

【Python深度学习】深度学习入门介绍

引言 深度学习是人工智能领域中最受关注和研究的子领域之一&#xff0c;它在计算机视觉、自然语言处理、语音识别、推荐系统等各个领域都有广泛的应用。本文将详细介绍深度学习的发展历史、不同类型、应用领域以及未来发展前景。 1、深度学习的发展历史 深度学习的起源可以追溯…...

【Linux系统编程】进程概念与基本创建

文章目录 1. 进程的概念2. 进程描述—PCB3. task_struct—PCB的一种4. task_ struct内容分类5. 查看进程 这篇文章我们来学习下一个概念——进程 1. 进程的概念 那什么是进程呢&#xff0c;我们该如何理解它呢&#xff1f; 如果我们打开电脑的任务管理&#xff1a; 我们看到这…...

webpack:详解CopyWebpackPlugin,复制的同时修改文件内容

摘要 CopyWebpackPlugin 是一个强大的 Webpack 插件&#xff0c;用于将文件从源目录复制到构建目录。在本文中&#xff0c;我们将探讨 CopyWebpackPlugin 的一些常用 API&#xff0c;并提供示例代码。 在构建 Web 应用程序时&#xff0c;通常需要将一些静态文件&#xff08;如…...

Twin-Builder—系统级多物理域数字孪生平台

Twin Builder是ANSYS公司系统仿真业务的核心产品&#xff0c;是一款跨学科多领域系统仿真软件和数字孪生平台。能够实现复杂系统的建模、仿真和验证&#xff0c;基于IIoT物联网平台对数字孪生体进行集成、部署与运行&#xff0c;在完成复杂系统功能、性能的验证和优化的同时&am…...

用selenium和xpath定位元素并获取属性值以及str字符型转json型

页面html如图所示&#xff1a; 要使用xpath定位这个div元素&#xff0c;并且获取其属性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的电影院管理系统设计与实现

前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌&#x1f497; &#x1f447;&#x1f3fb;…...

Linux Static Key原理与应用

文章目录 背景1. static-key的使用方法1.1. static-key定义1.2 初始化1.3 条件判断1.4 修改判断条件 2、示例代码参考链接 背景 内核中有很多判断条件在正常情况下的结果都是固定的&#xff0c;除非极其罕见的场景才会改变&#xff0c;通常单个的这种判断的代价很低可以忽略&a…...

linux ssh 禁止指定用户通过ssh登录

Linux 禁止用户或 IP通过 SSH 登录 限制用户 SSH 登录 1.只允许指定用户进行登录&#xff08;白名单&#xff09;&#xff1a; 在 /etc/ssh/sshd_config 配置文件中设置 AllowUsers 选项&#xff0c;&#xff08;配置完成需要重启 SSHD 服务&#xff09;格式如下&#xff1a…...

快速学习Netty

Netty框架探索&#xff1a;助力高效网络编程 一、Netty是个啥&#xff1f;二、“Hello World”服务器端实现&#xff08;Server&#xff09;客户端实现&#xff08;Client&#xff09;思考&#x1f914; 三、Netty的核心组件EventLoopChannelChannelPipelineChannelHandlerByte…...

基于算法竞赛的c++编程(28)结构体的进阶应用

结构体的嵌套与复杂数据组织 在C中&#xff0c;结构体可以嵌套使用&#xff0c;形成更复杂的数据结构。例如&#xff0c;可以通过嵌套结构体描述多层级数据关系&#xff1a; struct Address {string city;string street;int zipCode; };struct Employee {string name;int id;…...

Qt Widget类解析与代码注释

#include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this); }Widget::~Widget() {delete ui; }//解释这串代码&#xff0c;写上注释 当然可以&#xff01;这段代码是 Qt …...

深入理解JavaScript设计模式之单例模式

目录 什么是单例模式为什么需要单例模式常见应用场景包括 单例模式实现透明单例模式实现不透明单例模式用代理实现单例模式javaScript中的单例模式使用命名空间使用闭包封装私有变量 惰性单例通用的惰性单例 结语 什么是单例模式 单例模式&#xff08;Singleton Pattern&#…...

多模态大语言模型arxiv论文略读(108)

CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题&#xff1a;CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者&#xff1a;Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...

Spring AI与Spring Modulith核心技术解析

Spring AI核心架构解析 Spring AI&#xff08;https://spring.io/projects/spring-ai&#xff09;作为Spring生态中的AI集成框架&#xff0c;其核心设计理念是通过模块化架构降低AI应用的开发复杂度。与Python生态中的LangChain/LlamaIndex等工具类似&#xff0c;但特别为多语…...

蓝桥杯 冶炼金属

原题目链接 &#x1f527; 冶炼金属转换率推测题解 &#x1f4dc; 原题描述 小蓝有一个神奇的炉子用于将普通金属 O O O 冶炼成为一种特殊金属 X X X。这个炉子有一个属性叫转换率 V V V&#xff0c;是一个正整数&#xff0c;表示每 V V V 个普通金属 O O O 可以冶炼出 …...

VM虚拟机网络配置(ubuntu24桥接模式):配置静态IP

编辑-虚拟网络编辑器-更改设置 选择桥接模式&#xff0c;然后找到相应的网卡&#xff08;可以查看自己本机的网络连接&#xff09; windows连接的网络点击查看属性 编辑虚拟机设置更改网络配置&#xff0c;选择刚才配置的桥接模式 静态ip设置&#xff1a; 我用的ubuntu24桌…...

代码随想录刷题day30

1、零钱兑换II 给你一个整数数组 coins 表示不同面额的硬币&#xff0c;另给一个整数 amount 表示总金额。 请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额&#xff0c;返回 0 。 假设每一种面额的硬币有无限个。 题目数据保证结果符合 32 位带…...

Java毕业设计:WML信息查询与后端信息发布系统开发

JAVAWML信息查询与后端信息发布系统实现 一、系统概述 本系统基于Java和WML(无线标记语言)技术开发&#xff0c;实现了移动设备上的信息查询与后端信息发布功能。系统采用B/S架构&#xff0c;服务器端使用Java Servlet处理请求&#xff0c;数据库采用MySQL存储信息&#xff0…...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...