C程序的编译过程

目录

一、GCC编译器

二、编译过程

1、预处理(Preprocessing)

2、编译(Compilation)

3、汇编(Assembly)    

4、链接(Linking)

 三、秋招真题演练


一、GCC编译器

        在这里,先给大家简单介绍一下GCC编译器,相信对gcc并不陌生。GCC(GNU Compiler Collection,GNU编译器套件)是由 GNU 开发的编程语言译器。 GNU编译器套件包括C、C++、 Objective-C、 Java、 Ada 和 Go语言前端,也包括了这些语言的库(如 libstdc++,libgcj等)。

        相信大家平时也没少使用gcc编译器,但是却很少有人去研究gcc的编译流程。简单来说,编程语言分为机器语言、汇编语言、高级语言。而我们常使用的C语言属于高级语言,gcc编译器就是将我们的C语言源程序变为汇编语言,最终变成计算机可识别的机器语言。

        接下来叫我们一起来具体看看C程序的编译过程吧!

二、编译过程

        一个C语言从源程序到可执行代码分成四个步骤,分别是:预处理、编译、汇编、链接。先给大家看一下流程图,然后我们在一条一条进行学习。

        接下来,叫我们一起来深入探讨一下吧!

1、预处理(Preprocessing)

         预处理是读取c源程序,经过处理,生成一个.i文件,该文件的含义与源文件是相同的,但是没有宏定义、没有条件编译指令、没有特殊符号的输出文件。

        .i文件是如何生成的呢?这就需要我们来看一下预处理都干了哪些事吧!

(1)删除所有的注释

        注释不属于程序代码,它们是为了方便人理解代码,对程序的运行没有特别作用。

(2)宏扩展

        将所有的#define删除,并展开所有的宏定义

(3)条件预编译指令

        处理所有的条件预编译指令,比如#if、#ifdef、#elif、#else、#endif等

(4)文件包含

        在预处理期间包含文件会导致在源代码中添加文件名的全部内容,从而替换 #include<文件名> 指令。

        在预处理前,我先编写一个C源程序hello.c,代码如下:

/*hello.c源文件*/

#include <stdio.h>
#define TIMES 5

int main(int argc,char *argv[])
{
    int     i;  
    for(i=0; i<TIMES; i++)
    {   
        printf("Hello world\n");
    }   
    return 0;
}

        通常使用如下预处理指令:

gcc -E hello.c -o hello.i

        经过预处理后,得到hello.i文件,该文件还是C语言源代码,我们可以进行查看,大家可以试试,因为比较长,这里就给出部分截图了。

2、编译(Compilation)

         编译程序就是通过词法分析和语法分析,在确认所有的指令都符合语法规则之后,将其翻译成等价的中间代码表示或汇编代码。

        通常使用如下命令进行编译生成汇编文件。

gcc -S hello.i -o hello.s

        经过编译处理后,得到一个hello.s文件,当我们查看查看该文件时,我们发现.s文件已经是一个汇编语言编写的文件了,没有学过汇编语言的同学已经看不懂了吧(由于代码较长,下面只给部分截图进行参考)

3、汇编(Assembly)    

        使用汇编程序将程序集代码(.s文件)转换为机器可理解的代码(二进制/十六进制形式)。汇编程序是一个预先编写的程序,它将汇编代码转换为机器代码。它从程序集代码文件中获取基本指令,并将其转换为特定于计算机类型(成为目标代码)的二进制/十六进制代码。

        目标文件与程序集文件同名,存放的是与源程序等效的目标的机器语言代码。在UNIX操作系统中为.o文件。目标文件由段组成,通常一个目标文件中至少有两个段:

(1)代码段:该段所包含的主要是程序的指令,该段一般是可读和可执行的,但一般不可写。

(2)数据段:主要存放程序中要用到的各种常量、全局变量、静态的数据。一般数据段都是可读,可写,可执行的。

        通常可以使用如下命令进行汇编操作

 gcc -c hello.s -o hello.o

        经过汇编操作,我们得到了hello.o文件。经过查看,我们发现已经是一堆乱码,但其实这才是机器可以识别的二进制文件。

4、链接(Linking)

        经过汇编操作,文件已经成为了计算机可识别的二进制文件,那我们可以立即执行吗?让我们实践操作一下。

        为什么会出现这种情况呢?其实啊,我们还有很多问题没有解决,比如说,我们在该源文件中调用了printf函数,但是目前文件中并没有该函数的定义。此时就需要链接来解决该问题了,链接的主要任务就是将有关的目标文件彼此相连接,使得所有的目标文件成为一个能够被操作系统装入执行的统一整体,也就是可执行程序。

        根据库函数的链接方式的不同,链接处理可分为两种:

(1) 静态链接

        静态链接是指在编译阶段直接把静态库加入到可执行文件中去(.o文件与链接库.a文件拼接在一起),如图所示:

        通常我们可以使用如下命令,利用静态链接生成可执行文件:

gcc hello.o -o hello -static

(2)动态链接

        动态链接则是指链接阶段仅仅只加入一些描述信息,而程序执行时再从系统中把相应动态库加载到内存中去,如图所示:

        通常我们可以使用如下命令,利用动态链接生成可执行文件: 

gcc hello.o -o hello 

        接下来我们来看一看静态链接和动态链接有什么区别呢?

        我们可以使用如下命令查看静态链接生成的可执行文件和动态链接生成的可执行文件所占内存大小:

du -h hello

        查看后,分别为:

静态链接:

动态链接:

         我们可以看到,静态链接生成的可执行文件所占内存远远大于动态链接所生成的可执行文件。

        除此之外,我们还要知道一点二者的区别:静态链接在编译期完成,动态链接在运行期完成。

        最后,在经过了预处理、编译、汇编、链接后,我们使用如下命令执行可执行文件,来看看我们源文件的编译是否成功:

./hello

 三、秋招真题演练

  (该题为牛客网小米公司2022年嵌入式工程师面试题第2题)

题目:C编译到执行的4个阶段

参考答案:

        在C语言编译运行的过程中,可以分为4个主要的阶段,包括预处理、编译、汇编和链接。

        预处理阶段(Preprocessing):在预处理阶段,编译器会处理源文件,包括展开宏定义、头文件的展开、条件编译等,生成一个经过预处理后的文本文件。此阶段的结果是一个以 .i 为扩展名的文件。

        编译阶段(Compilation):在编译阶段,编译器将经过预处理的文本文件翻译成汇编代码。汇编代码是一种低级的、与机器相关的语言。此阶段的结果是一个以 .s 为扩展名的文件。

        汇编阶段(Assembly):在汇编阶段,汇编器将汇编代码转换成机器可以执行的指令。此阶段的结果是一个以 .o 为扩展名的文件。

        链接阶段(Linking):在链接阶段,连接器将目标文件以及一些必要的库文件进行链接,生成可执行文件。此阶段的结果是一个没有扩展名的可执行文件。

         以上是C语言编译执行的基本阶段,具体的实现方式可能因编译器和操作系统的不同而有所不同。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/416991.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux系统Jenkins工具web配置

Jenkins工具配置 插件配置系统配置系统工具配置 插件配置 下载 Maven Integration Pipeline Maven lntegration gitlab Generic webhook Trigger nodejs Blue ocean系统配置 系统配置结束系统工具配置

androidframework开发面试,阿里P8成长路线

字节跳动Android面经 一面问的 Java 和 Android 基础 1、Jvm虚拟机 2、messageQueue会不会阻塞ui线程 3、对象锁和类锁 4、之字形打印树 5、还有其他的 《Android学习笔记总结最新移动架构视频大厂安卓面试真题项目实战源码讲义》 **完整开源项目&#xff1a;docs.qq.com/doc…

Linux命名管道

Linux匿名管道-CSDN博客 目录 1.原理 2.接口实现 3.模拟日志 Linux匿名管道-CSDN博客 这上面叫的是匿名管道&#xff0c;不要将两者搞混&#xff0c;匿名管道说的是两个有血缘关系的进程相互通信&#xff0c;但是命名管道就是两个没有关系的管道相互通信。 1.原理 和匿名…

解密犯罪时间 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 警察在侦破一个案件时&#xff0c;得到了线人给出的可能犯罪时间&#xff0c;形如 HH:MM 表示的时刻。 根据警察和线人的约定&#xff0c;为了隐蔽&#xff0c;该…

RabbitMQ实战学习

RabbitMQ实战学习 文章目录 RabbitMQ实战学习RabbitMQ常用资料1、安装教程2、使用安装包3、常用命令4、验证访问5、代码示例 一、RabbitMQ基本概念1.1. MQ概述1.2 MQ 的优势和劣势1.3 MQ 的优势1. 应用解耦2. 异步提速3. 削峰填谷 1.4 MQ 的劣势1.5 RabbitMQ 基础架构1.6 JMS 二…

图形系统开发实战课程:进阶篇(上)——8.图形样式

图形开发学院&#xff5c;GraphAnyWhere 课程名称&#xff1a;图形系统开发实战课程&#xff1a;进阶篇(上)课程章节&#xff1a;“图形样式”原文地址&#xff1a;https://www.graphanywhere.com/graph/advanced/2-8.html 第八章 图形样式 1. 填充和描边 \quad 在图形系统实战…

vision mamba 运行训练记录,解决bimamba_type错误

下载vision mamba github上的项目后&#xff0c;解压&#xff0c;进入文件夹项目&#xff0c;然后配环境 unzip Vim-main.zip cd Vim-mainconda create -n mamba python3.10.13conda activate mamba pip install torch2.1.1 torchvision0.16.1 torchaudio2.1.1 --index-url ht…

java面试(网络)

TCP和UDP有什么区别&#xff1f;TCP三次握手不是两次&#xff1f; TCP&#xff1a;面向连接&#xff0c;可靠的&#xff0c;传输层通信协议。点对点&#xff0c;占用资源多&#xff0c;效率低。 UDP&#xff1a;无连接&#xff0c;不可靠&#xff0c;传输层通信协议。广播&…

照片中不想要的部分怎么去除?教你几个小妙招

照片在我们的生活中占据着无可替代的地位。它们是我们生活的缩影&#xff0c;定格住我们的瞬间&#xff0c;记录着我们的记忆&#xff0c;让我们可以随时随地回顾过去的美好时光。无论是家庭聚会、旅行、婚礼还是其他重要的场合&#xff0c;我们都会用照片来捕捉这些珍贵的时刻…

springboot 实现本地文件存储

springboot 实现本地文件存储 实现过程 上传文件保存文件&#xff08;本地磁盘&#xff09;返回文件HTTP访问服务器路径给前端&#xff0c;进行效果展示 存储 服务端接收上传的目的是提供文件的访问服务&#xff0c;对于SpringBoot而言&#xff0c;其对静态资源访问提供了很…

【Java设计模式】三、

文章目录 0、案例&#xff1a;咖啡屋1、简单工厂模式 静态工厂&#xff08;不属于23种之列&#xff09;2、工厂方法模式3、抽象工厂模式4、建造者模式5、原型设计模式 0、案例&#xff1a;咖啡屋 模拟咖啡店点餐。咖啡有多种&#xff0c;抽象类&#xff0c;子类为各种咖啡。咖…

element ui富文本编辑器的使用(quill-editor)

引用组件 <el-form-item label"内容"><editor v-model"obj.activity_content" :min-height"192"/> </el-form-item> 组件封装 <template><div><el-upload:action"uploadUrl":before-upload"…

Node.js如何进行性能监控和分析

Node.js作为一款流行的后端开发技术&#xff0c;其性能监控和分析对于保证系统稳定性和性能优化至关重要。在本文中&#xff0c;我们将探讨Node.js如何进行性能监控和分析&#xff0c;以便开发者能够更好地了解系统运行状况并进行必要的优化。 为什么进行性能监控和分析&#…

力扣刷题:141.环形链表

题目&#xff1a; 给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中…

idea集成git详解教程(实用篇)

0.Git常用命令 Git常用命令-CSDN博客 1.下载git Git - Downloads 一路傻瓜式安装即可&#xff08;NEXT&#xff09; 2.软件测试 在Windows桌面空白处&#xff0c;点击鼠标右键&#xff0c;弹出右键菜单 Git软件安装后&#xff0c;会在右键菜单中增加两个菜单 Git GUI He…

GTID的使用原理

一.简介 GTID是MySQL 5.6的新特性&#xff0c;其全称是Global Transaction Identifier&#xff0c;可简化MySQL的主从切换以及Failover。GTID用于在binlog中唯一标识一个事务。当事务提交时&#xff0c;MySQL Server在写binlog的时候&#xff0c;会先写一个特殊的Binlog Event&…

机器学习提升秘籍:Scikit-learn学习网站全攻略!

介绍&#xff1a;是一个开源的Python机器学习库&#xff0c;它提供了一整套用于数据挖掘和数据分析的工具&#xff0c;包括各种分类、回归、聚类和降维算法以及模型评估、选择和数据预处理等功能。以下是关于Scikit-learn的一些详细介绍&#xff1a; 算法覆盖广泛&#xff1a;S…

基于SSM SpringBoot vue服装物流管理系统

基于SSM SpringBoot vue服装物流管理系统 系统功能 首页 图片轮播 人个中心 登录注册 后台管理: 登录注册 个人中心 货物信息管理 货物入库管理 订单信息管理 商品出库管理 快递追踪管理 用户管理 供应商信息管理 盘点信息管理 管理员管理 开发环境和技术 开发语言&#xf…

C++初阶:模版相关知识的进阶内容(非类型模板参数、类模板的特化、模板的分离编译)

结束了常用容器的介绍&#xff0c;今天继续模版内容的讲解&#xff1a; 文章目录 1.非类型模版参数2.模板的特化2.1模版特化引入和概念2.2函数模版特化2.3类模板特化2.3.1全特化2.3.1偏特化 3. 模板分离编译3.1分离编译概念3.2**模板的分离编译**分析原因 1.非类型模版参数 模板…

消息中间件之RocketMQ源码分析(二十二)

Broker主从同步流程 配置数据同步流程 配置数据包含4种类型:Topic配置、消费者位点、延迟位点、订阅关系配置。每种配置数据由一个继承自ConfigManager的类来管理&#xff0c;继承关系如图。Slave如何从Master同步这些配置呢?我们先来看一下初始化服务的步骤 第一步:Maste…