【C语言】 —— 编译和链接

【C语言】 —— 编译和链接

  • 一、编译环境和运行环境
  • 二、翻译环境
    • 2.1、 预处理
    • 2.2、 编译
      • (1)词法分析
      • (2)语法分析
      • (3)语义分析
    • 2.3、 汇编
    • 2.4、链接
  • 三、运行环境

一、编译环境和运行环境

  平时我们说写 C语言 代码,写程序,不难发现:其实写出来的都是 t e s t test test. c c c t e s t test test. h h h 等源文件和头文件。我们直接打开他们,是可以直接看懂的,这也就说明了他们其实是文本文件。但是计算机是看不懂他们的,计算机只能识别二进制指令,无法对文件中的代码直接执行。这时就需要将 C语言 代码进行处理变成二进制的指令。
  
  而将代码处理成二进制指令正是编译器需要做的事情。
  
ANCI C 的任何一种实现中,存在两个不同的环境:

  1. 翻译环境:在这个环境中源代码被转换成可执行的机器指令(二进制指令)
  2. 执行环境:它用于实际执行代码

  

二、翻译环境

  那翻译环境是怎么将源代码转换为可执行的机器指令的呢?这里我们就得展开讲解一下翻译环境所做的事情
  
  其实翻译环境是由编译链接两大过程组成,而编译又可以分解成:预处理(有些书也叫预编译)、编译汇编三个过程。

在这里插入图片描述

  
一个C语言的项目中可能由多个 . c c c 文件一起构建,那多个 . c c c 文件如何生成可执行程序呢?

  • 多个 . c c c 文件单独经过编译器,编译处理生成对应的目标文件
  • W i n d o w s Windows Windows 环境下的目标文件的后缀是 .obj,在 L i n u s Linus Linus环境下目标文件的后缀是 .o
  • 多个目标文件链接库一起经过连接器处理生成最终的可执行程序
  • 链接库是指运行时库(它是支持程序运行的基本函数集合)、C语言库函数或者第三方库

  这里需提一下,我们所用的 V S 2022 VS2022 VS2022 是一种集成开发环境,包括:编辑器编译器链接器调试器。而 c l cl cl. e x e exe exe 是其编译器, l i n k link link. e x e exe exe 是其链接器
  

在这里插入图片描述

  我们可以在 L i n u s Linus Linus 服务器、 g c c gcc gcc 的环境下对链接和编译各个阶段进行观察
  
  

2.1、 预处理

  在预处理阶段,源文件和头文件会被处理成 .i 为后缀的文件。

  在 g c c gcc gcc 中,将 .c 文件处理成 .h 文件,命令如下:

gcc -E test.c -o test.i

  
  预处理阶段主要处理那些源文件中 # 开始的编译指令。比如:# i n c l u d e include include,# d e f i n e define define,处理的规则如下:

  • 将所有的 # d e f i n e define define 删除展开所有的宏定义
  • 处理所有的条件编译指令,如:#if#ifdef#elif#else#endif
  • 处理 # i n c l u d e include include 预编译指令,将包含的头文件的内容插入到该预编译指令的位置。这个过程是递归进行的,也就是说被包含的头文件也可能包含其他文件。
  • 删除所有注释
  • 添加行号文件名标识,方便后续编译器生成调试信息等
  • 保留所有的 # p r a g m a pragma pragma 的编译器指令,编译器后续会使用

  经过预处理后的 . i .i .i 文件不再包含宏定义,因为宏已经被展开。并且包含的头文件被插入.i 文件中。所以我们无法知道宏定义或者头文件是否包含正确的时候,可以查看预处理后的 . i .i .i 文件来确认。
  
t e s t test test. c c c 文件

在这里插入图片描述

  
t e s t test test. i i i 文件

在这里插入图片描述

   . i .i .i 文件只有输入指令生成后我们才能看到,正常情况下生成中间文件编译器用完就删掉了。
  
  

2.2、 编译

  编译过程就是将预处理后的文件进行一系列的:词法分析语法分析语义分析及优化,生成相应的汇编代码文件

编译过程的命令如下:

gcc -S test.i -o test.s

  编译过程最终会生成 .s 的文件,它里面放的是汇编代码。其实编译阶段整体上就是将 C 代码转换成汇编代码
  
t e s t . s test.s test.s 文件

在这里插入图片描述

  那编译过程具体是做了什么工作呢?
  他们分别是:词法分析语法分析语义分析及优化
  下面让我们一起简单了解
  
  假设有下面的代码,在进行编译时会时编译器怎么做呢

array[index] = (index + 4) * (2 + 6);

  

(1)词法分析

  将源代码程序输入扫描器,扫描器的任务就是简单的进行词法分析把代码中的字符分割成一系列的记号(关键字、标识符、字面量、特殊字符等)。
  

上述代码进行词法分析后得到了 16 个记号:

记号类型记号类型
array标识符4数字
[左方括号)右圆括号
index标识符*乘号
]右方括号(左圆括号
=赋值2数字
(左圆括号+加号
index标识符6数字
+加号)右圆括号

  

(2)语法分析

  接下来则是语法分析语法分析器会对扫描产生的记号进行语法分析,从而产生语法树。这些语法树是以表达式为节点的树

在这里插入图片描述

  

(3)语义分析

  由语义分析器来完成语义分析,即对表达式的语法层面分析。编译器所能做的分析是语义的静态分析。静态语义分析通常包括声明和类型的匹配。这个阶段会报告错误的语法信息

在这里插入图片描述

  

2.3、 汇编

  汇编是指通过汇编器将汇编代码转变成机器可执行的指令,每一个汇编语句几乎都对应一条机器指令。就是按照汇编指令和机器指令的对照表一一的进行翻译,也不做指令优化

  汇编的命令如下:

gcc -c test.s -o test.o

  经过汇编处理后文件即为目标文件( . o b j .obj .obj / . o .o .o)目标文件为二进制文件,无法通过文本编辑器打开

  

2.4、链接

  链接是一个复杂的过程,链接的时候需要把一堆文件链接在一起才生成可执行程序。
  链接的过程主要包括:地址和空间分配符号决议重定位等这些步骤。
  
  链接主要解决的是一个项目中多个文件、多模块之间互相调用的问题
  比如:现在有两个文件( t e s t . c test.c test.c a d d . c add.c add.c
  
t e s t . c test.c test.c 文件

#incldue<stdio.h>//声明外部函数
extern int Add(int x, int y);
//声明外部的全局变量
extern int g_val;int main()
{int a = 10;int b = 20;int c = Add(10, 20);printf("%d\n", c);return 0;
}

  
A d d . c Add.c Add.c 文件

int g_val = 2024;int Add(int x, int y)
{return x + y;
}

  
  为什么在 Add.c 中定义的文件在 test.c 文件中声明一下就可以使用呢?
  这里进行简单的了解
  
  经过前面的学习,我们知道每一个源文件( . c .c .c)经过编译过程后都会生成自己的目标文件 . o .o .o / . o b j .obj .obj
  
  在编译的过程中,会对代码中的符号进行符号的汇总,并形成相应的符号表,符号表中会存储符号相对应的地址。在产生 t e s t . c test.c test.c 文件的符号表时,遇到只有声明而未定义的符号 Addg_val 时,会暂时将其地址搁置

在这里插入图片描述

  

  到了编译过程,编译器会将多个目标文件链接在一起(目标文件的格式是一样的,并且是分段的形式),从而生成可执行程序(可执行策划给你续最终也是如目标文件一样的分段形式)
  
  在合并过程中,符号表也需要合并成一份。合并后的符号表每个符号只能有一份,那 Addg_val 符号自然用其有效地址的那一份,这样符号表就完成了合并。通过 A d d Add Add 的地址,就自然而然能找到 A d d Add Add 函数了。
  

在这里插入图片描述

  而上述对地址的修正过程被叫做:重定位
  
  前面我们非常简洁的讲解了一个 C 的程序是如何编译和链接,到最终生成可执行程序的过程,其实很多内部的细节无法展开讲解。
  比如:目标文件的格式 e l f elf elf,链接底层实现中的空间与地址分配,符号解析和重定位等,如果你有兴趣,可以看 《程序员的自我修养》 一书来详细了解。
  
  

三、运行环境

  运行环境实际上是非常复杂的,我们这里简单了解了解

  1. 程序必须载入内存中。在有操作系统的环境中:一般这个由操作系统完成。在独立的环境中,程序的载入必须由手动安排(单片机烧板子),也可以通过可执行代码置入只读内存来完成。
  2. 程序的执行便开始。接着便调用 m a i n main main 函数
  3. 开始执行程序代码。这个时候程序将使用一个运行时堆栈(函数栈帧),存储函数的局部变量返回地址。程序同时也可以使用静态(static)内存,存储于静态内存中的变量在程序的整个执行过程一直保留他们的值。
  4. 终止程序。正常终止 m a i n main main 函数;也有可能是意外终止

  
  
  
  
  


  好啦,本期关于编译和链接的知识就介绍到这里啦,希望本期博客能对你有所帮助。同时,如果有错误的地方请多多指正,让我们在C语言的学习路上一起进步!

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

C语言中32位浮点数的格式

以 GNU C为例&#xff0c;它遵循 IEEE 754-2008标准中制定的浮点表示规范。在该规范中定义了 5种不同大小的基础二进制浮点格式&#xff0c;包括&#xff1a;16位&#xff0c;32位&#xff0c;64位&#xff0c;128位&#xff0c;256位。其中&#xff0c;32位的格式被用作标准 C…

使用AOP思想实现开闭原则下的流水日志输出

主要实现思想&#xff1a; 通过实现Convert接口来抽取公共组件&#xff0c;获取想要的标准模型。 现在有两个订单场景&#xff0c;一个保存订单&#xff0c;一个为更新订单。构造如下的服务类&#xff1a; import org.springframework.stereotype.Service;Service public clas…

SHAP(SHapley Additive exPlanations)基于XGBoost模型的可解释机器学习

模型可解释性 这是一个关于错误解释机器学习模型的危险以及正确解释它的价值的故事。如果您发现诸如梯度提升机或随机森林之类的集成树模型的鲁棒准确性很有吸引力&#xff0c;但也需要解释它们&#xff0c;那么我希望您发现这些信息有用且有帮助。 试想一下&#xff0c;我们…

julia系列17: tsp问题代码整理

1. 常用库和基础函数 这里是优化版的函数&#xff1a; using TSPLIB,LKH,Distances,PyPlot MaxNum 10000 tspreadTSPLIB(:att48) dist [round.(Int,euclidean(tsp.nodes[i,:],tsp.nodes[j,:])) for i in 1:tsp.dimension,j in 1:tsp.dimension]; pos(tsp::TSP,t::Vector{In…

uniapp跨域问题解决

找到menifest文件&#xff0c;在文件的最后添加如下代码&#xff1a; // h5 解决跨域问题"h5":{"devServer": {"proxy": {"/adminapi": {"target": "https://www.demo.com", // 目标访问网址"changeOrigin…

httpd目录显示乱码问题

vim /etc/httpd/conf/httpd.conf 在<Directory “/var/www/html”>下添加&#xff1a; IndexOptions CharsetUTF-8重启httpd: systemctl restart httpd.service还是不好看&#xff0c;调整下显示宽度&#xff0c;还是这个位置&#xff1a; <Directory “/var/www/ht…

区块链论文速读A会-ISSTA 2023(2/2)如何检测DeFi协议中的价格操纵漏洞

Conference&#xff1a;ACM SIGSOFT International Symposium on Software Testing and Analysis (ISSTA) CCF level&#xff1a;CCF A Categories&#xff1a;Software Engineering/System Software/Programming Languages Year&#xff1a;2023 第1~5篇区块链文章 请点击此…

C++面向对象的常见面试题目(一)

1. 面向对象的三大特征 &#xff08;1&#xff09;封装&#xff1a;隐藏对象的内部状态&#xff0c;只暴露必要的接口。 #include <iostream> #include <string>// 定义一个简单的类 Person class Person { private: // 私有成员&#xff0c;外部不可直接访问std…

华为机试HJ37统计每个月兔子的总数

华为机试HJ37统计每个月兔子的总数 题目&#xff1a; 想法&#xff1a; 上述题目实际是一个斐波那契数列&#xff0c;利用斐波那契数列对问题进行求解 input_number int(input())def fib(n):if n < 2:return 1else:n_1 1n_2 1count 2while count < n:n_1, n_2 n_…

【AI资讯】可以媲美GPT-SoVITS的低显存开源文本转语音模型Fish Speech

Fish Speech是一款由fishaudio开发的全新文本转语音工具&#xff0c;支持中英日三种语言&#xff0c;语音处理接近人类水平&#xff0c;使用Flash-Attn算法处理大规模数据&#xff0c;提供高效、准确、稳定的TTS体验。 Fish Audio

机器学习Day12:特征选择与稀疏学习

1.子集搜索与评价 相关特征&#xff1a;对当前学习任务有用的特征 无关特征&#xff1a;对当前学习任务没用的特征 特征选择&#xff1a;从给定的特征集合中选择出相关特征子集的过程 为什么要特征选择&#xff1f; 1.任务中经常碰到维数灾难 2.去除不相关的特征能降低学习的…

Git注释规范

主打一个有用 代码的提交规范参考如下&#xff1a; init:初始化项目feat:新功能&#xff08;feature&#xff09;fix:修补bugdocs:文档&#xff08;documentation&#xff09;style:格式&#xff08;不影响代码运行的变动&#xff09;refactor:重构&#xff08;即不是新增功能…

计算机网络之令牌环

1.令牌环工作原理 令牌环&#xff08;Token Ring&#xff09;是一种局域网&#xff08;LAN&#xff09;的通信协议&#xff0c;最初由IBM在1984年开发并标准化为IEEE 802.5标准。在令牌环网络中&#xff0c;所有的计算机或工作站被连接成一个逻辑或物理的环形拓扑结构。网络中…

排序(2)

我们在排序&#xff08;1&#xff09;中说到选择排序的代码&#xff1a; void SelectSort(int* a,int n) {int begin0,endn-1;int minibegin,maxbegin;for(int ibegin1;i<end;i){if(a[i]>a[max]){maxii;}if(a[i]<a[mini]){minii;}begin;--end;}Swap(&a[beign],&a…

SKF轴承故障频率查询

1&#xff0c;第一步&#xff1a;搜索轴承型号 skf官网 2&#xff0c;第二步&#xff1a;查询故障频率。 第三步&#xff1a;

尚品汇-(十四)

&#xff08;1&#xff09;提交git 商品后台管理到此已经完成&#xff0c;我们可以把项目提交到公共的环境&#xff0c;原来使用svn&#xff0c;现在使用git 首先在本地创建ssh key&#xff1b; 命令&#xff1a;ssh-keygen -t rsa -C "your_emailyouremail.com" I…

落日余晖映晚霞

落日余晖映晚霞&#xff0c;立于海滨&#xff0c;望夕阳余晖洒于波光粼粼之上&#xff0c;金光跳跃&#xff0c;若繁星闪烁&#xff0c;耀人心目。 海风轻拂&#xff0c;心境宁静&#xff0c;凡尘俗务皆于此刹那消散&#xff0c;思绪万干&#xff0c;或忆往昔点滴&#xff0c;或…

刷爆leetcode第十期

题目一 相同的树 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 首先我们要来判断下它们的根是否相等 根相等的话是否它们的左子树相等 是否…

在CMD中创建虚拟环境并在VSCode中使用和管理

1. 使用Conda创建虚拟环境 在CMD或Anaconda Prompt中执行以下代码以创建一个新的虚拟环境&#xff1a; conda create -n my_env python 3.8 这样会创建一个名为 my_env 的环境&#xff0c;并在Anaconda环境目录下生成一个相应的文件夹&#xff0c;包含该虚拟环境所需的所有…

GD32实战篇-双向数控BUCK-BOOST-BOOST升压理论基础

本文章基于兆易创新GD32 MCU所提供的2.2.4版本库函数开发 向上代码兼容GD32F450ZGT6中使用 后续项目主要在下面该专栏中发布&#xff1a; https://blog.csdn.net/qq_62316532/category_12608431.html?spm1001.2014.3001.5482 感兴趣的点个关注收藏一下吧! 电机驱动开发可以跳转…