Linux---​代码运行-程序的翻译过程

前言

  我们平常用C/C++语言写代码的时候,运行只是靠编译器,点一下运行按钮就会出现我们代码运行的结果,那我们的代码究竟是怎么得到最终结果的呢?还是非常值得我们去了解与学习的。

一、翻译过程

> 预处理

预处理功能主要包括宏定义,文件包含,条件编译,去注释等。

1、宏定义、文件包含、去注释

    我们现在写一个实例代码,让大家更好的了解

上述代码可以让我们很好的验证预处理的功能。

我们正常编译时,会直接给出一个含有最终结果的可执行文件,但我们想要查看预处理之后的总体代码应该怎么看呢?

执行命令:

g++ -E 文件名 -o 可执行文件名(在预处理这里,后缀名一定要是.i)

选项“-E”,该选项的作用是让 gcc 在预处理结束后停止编译过程。 选项“-o”是指目标文件,“.i”文件为已经过预处理的C原始程序。

此时生成了一个含有预处理结果的文件,我们手动命名为了text.exe,我们打开:

  左边是我们原来写的代码文件text.cc,右边是经过预处理之后的文件text.i,我们通过对比可以发现这两个文件里面的内容差的不是一点半点,这一万七千多行最下面才和我们源代码有点相似,那上面多出来的那么多行就是我们的头文件的展开,是头文件里面的内容,预处理会把我们的有文件里面的内容拷贝进来,这也就是预处理的作用之一,最下面我们也可以看出,我们的M已经被替换成了100,也就是宏的替换,注释也经过预处理之后就不见了,预处理的功能也由此可见。

2、头文件的所在路径

  我们在text.cc文件的最开始可以看到,预处理阶段,会按照路径找到头文件,并将它拷贝进来

我们可以进入照这个路径查看头文件:

  我们可以看到我们常用的iostream、algorithm等头文件都在这里,这是因为我们在安装gcc/g++时都会首先把你C/C++中所需要的头文件安装下来,以防之后用的时候找不到。

3、条件编译 

  我以一个实例来讲述条件编译,就拿我们Xshell举例。Xsehll有学生版、企业版、专业版等版本,我当前使用的就是免费的学生版,每个版本的功能都各有不同,专业版和企业版的功能肯定要比学生版本的功能多。

  那在这里有一个疑问,在维护Xshell代码时,我们需要维护三份来对应不同的版本吗?

  其实只需要维护一份,就可以适应三个版本,这里写一个代码帮助大家理解。

我们在vim里面写入这样一串代码:

从上到下对应Xshell的学生版、企业版、专业版,功能依次增加。我们运行这串代码:

我们会发现,只运行了专业版部分的代码,我们在文件全局区域加上学生版条件v1的宏定义,比如:

运行之后我们会发现:

这次又只运行了学生版的代码。

所以我们可以通过一个这样的方式来进行一个代码的裁剪、功能的保留。

但我想要修改的话,每次打开真的太麻烦,所以我们在这里有一个比较方便的操作,我们不用打开文件,再编译代码时在命令行加上一段小命令即可。称为命令行宏定义。

命令:

gcc -D <条件> <文件名>

注意!我们需要先把源文件中的宏定义去除.

举例:

       

> 编译

  在这个阶段中,gcc 首先要检查代码的规范性、是否有语法错误等,以确定代码的实际要做的工作,在检查 无误后,gcc 把代码翻译成汇编语言。

  用户可以使用“-S”选项来进行查看,该选项只进行编译而不进行汇编,生成汇编代码。

命令:

gcc/g++ -S <预处理后的文件名,后缀为.i>

执行命令后后生成一个后缀为.s的文件。 

我们这里还是以预处理阶段用到的一个c++文件演示:

打开编译完的文件:

我们可以看到已经转化成了汇编语言。

> 汇编

汇编的作用是生成生成机器可识别代码,也就是二进制。

读者在此可使用选项“-c”就可看到汇编代码已转化为“.o”的二进制目标代码了

命令:

gcc/g++ -c <编译后的文件名,后缀为.s>

 实例:

我们打开汇编完的文件:

我是看不懂......

> 链接 (重要)

最后链接步骤,会生成我们的可执行文件或者库文件

执行命令:

gcc/g++ <汇编后生成的文件,后缀为.o>

执行这条命令就会生成我们最终的可执行文件,没有进行自定义命名的话,文件名默认就是a.out。

 我们也知道,计算机认识二进制语言,我们在汇编过程中已经将语言转化为了二进制语言,可是为生成的为什么不是可执行文件呢?为什么还需要链接这个步骤呢?

1、链接是什么?

  链接是我们的程序与链接的过程。是我们不曾知道的第三方库。也就是语言的标准库。

  标准库里包含了我们所需要的头文件,需要调用的函数等等,每个语言都有自己的一个标准库,就比如我们printf打印,我们写出来就可以用,但是在底层需要去库里调用这个函数的。

  我们可以通过指令:

ldd a.out

  查看我们该程序所用到的标准库:  其中,libc.so.6=>/lib64.libc.so.6(0x00007ff05c32e000)就是我们的默认动态链接库。

  就好比我们学校为我们提供图书馆,我们进入图书馆去读完一本书,读完再回去。待会作一个更未为详细的讲解。

2、怎么去链接?

在我们Linux下的库分两种库,分别是动态库和静态库:

  • 动态库文件后缀:.so
  • 静态库文件后缀:.a 

在与动态库或者静态库分别进行链接时,分别对应动态链接静态链接两种方式。

  • 静态库是指编译链接时,把库文件的代码全部加入(拷贝)到可执行文件中,因此生成的文件比较大,但在运行时也 就不再需要库文件了。
  • 动态库与之相反,在编译链接时并没有把库文件的代码加入到可执行文件中,而是在程序执行时由运行时 链接文件加载库(直接去库里面去执行),这样可以节省系统的开销。如前面所述的 libc.so.6 就是动态 库。gcc 在编译时默认使用动态库。

动态库和动态链接的优缺点:

1、不能丢失,一旦丢失,所有涉及到该库的程序都无法执行

2、节省资源

静态库与静态链接的优缺点:

1、一旦形成,与库无关

2、浪费资源。

如果我们想调用静态库,我们可以执行命令:

gcc -o <自定义生成文件名> <编译文件> -static -std=c99

生成可执行文件: 

 我们对比一下动静态链接生成的文件大小,我们再生成一个使用动态链接生成的可执行文件,默认名字为a.out。

我们可以看到,大小差了200倍!

使用静态库的时候,Linux默认是没有的,需要我们手动下载,需要执行命令:

sudo yum install -y glibc-static libstdc++-static

静态链接的应用场景:

  如果你编译的程序具有非常大的跨平台性的话,以后可能会部署在很多机器上,这时候你就可以静态链接,把你的二进制代码直接部署在其它机器上,这样我们的机器不依赖动态库,不用做过多的环境监测。

二、历史原因

  我们会有这样的疑问:为什么不能一步直接生成可执行文件呢?为什么要经过这么多麻烦的步骤?

>编程历史

1、二进制编程

  我们知道,在六七十年的时候,还没有C语言的时候,人们编程用的都是二进制编程,就是我们听过的打孔纸带

  穿孔纸带是早期计算机的储存介质,它将程序和数据转换二进制数码:带孔为1,无孔为0,经过光电输入机将数据输入计算机。所以当时的二进制编程是不需要编译器的!!!

  只不过这样太麻烦,当时会编程的都可以被称为科学家。后来人们为了提升效率,写出了汇编语言

2、汇编语言

  汇编语言, 即第二代计算机语言,用一些容易理解和记忆的缩写单词来代替一些特定的指令,例如:用"ADD"代表加法操作指令,"SUB"代表减法操作指令,以及"INC"代表增加1"DEC"代表减去1,"MOV"代表变量传递等等,通过这种方法,人们很容易去阅读已经完成的程序或者理解程序正在执行的功能,对现有程序的bug修复以及运营维护都变得更加简单方便。

  那汇编语言需不需要编译器呢?答案是肯定需要的

  因为计算机的硬件不认识字母符号,这时候就需要一个专门的程序把这些字符变成计算机能够识别的二进制数或机器语言。因为汇编语言只是将机器语言做了简单编译,所以并没有根本上解决机器语言的特定性。

3、C语言

  也就是我们现在经常使用的语言,在此我就不多介绍,在这里我想问的是,那我们C语言的编译又是什么样子的呢?是直接转化为二进制语言吗?

>编译器的自举

  在汇编语言发明的时候,如果没有编译器,那机器也就不会认识这所谓的汇编语言,毕竟计算机只认识二进制,所以我们就需要写一个编译器来将汇编语言转化为二进制,但是当时只有二进制编程,所以我们只能用二进制编程写出一个编译汇编语言的编译器!

  当又有了C语言时,我们又需要写一个编译C语言的编译器,但是话说回来,编译器真的好写吗?并不好写,所以说我们踩在前人的肩膀上,用汇编语言写出一个编译C语言的编译器,要比直接用二进制写一个编译C语言的编译器要容易的多。

  所以我们会存在编译汇编两个步骤,不可缺少。

  随着时代的进步,我们的编译器也在更新换代,二进制写出来的编译器,维护起来过于麻烦,既然编译器是软件,那我们也可以用二进制编译的汇编语言来写一个汇编语言编译的编译器!这里有点套娃的感觉,但是也挺好理解。从此之后,我们就可以用汇编语言写的编译器编译汇编语言,也可以用汇编语言来升级编辑器。

  那C语言呢?也是同理,我们可以用C语言写一个编译C语言的编译器,再经过汇编编译C的语言的编译器编译。就可以形成一个纯C的编译器。

 自己编译自己,就是编译器自举的过程。         

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

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

相关文章

java第二十三课 —— 继承

面向对象的三大特征 继承 继承可以解决代码复用&#xff0c;让我们的编程更加靠近人类思维&#xff0c;当多个类存在相同的属性&#xff08;变量&#xff09;和方法时&#xff0c;可以从这些类中抽象出父类&#xff0c;在父类中定义这些相同的属性和方法&#xff0c;所有的子…

虚拟淘宝-Virtual-Taobao论文解读(AAAI2019)

目录 1 论文简介 2 文章的主要贡献 3 文章技术的简要说明 4 技术的详细说明 4.1 GAN-SD&#xff1a;生成客户特征 4.2 MAIL&#xff1a;生成交互过程 4.3 ANC&#xff1a;动规范约束 5 实验设定及结果 6 结论 7 参考 1 论文简介 南京大学LAMDA团队的侍竞成、俞扬等…

【服务器硬件由 CPU、RAM、硬盘等组成,选购时需考虑应用需求、预算等。散热、安全、监控与维护亦重要,未来发展趋势包括高性能、低能耗和智能化。】

本人详解 作者:王文峰,参加过 CSDN 2020年度博客之星,《Java王大师王天师》 公众号:JAVA开发王大师,专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生,期待你的关注和支持!本人外号:神秘小峯 山峯 转载说明:务必注明来源(注明:作者:王文峰…

MySQL----索引的底层实现和原理

索引 在前面的文章中&#xff0c;我们分析了索引的分类、创建、删除以及索引的创建原则等&#xff0c;知道了创建索引的目的就是为了加速对表中的数据行的检索而创造的一种分散存储的数据结构。那么索引的底层结构是什么呢&#xff1f; 底层实现 数据库索引是存储在磁盘上的…

PDF标准详解(三)—— PDF坐标系统和坐标变换

之前我们了解了PDF文档的基本结构&#xff0c;并且展示了一个简单的hello world。这个hello world 虽然只在页面中显示一个hello world 文字&#xff0c;但是包含的内容却是不少。这次我们仍然以它为切入点&#xff0c;来了解PDF的坐标系统以及坐标变换的相关知识 图形学中二维…

OpenCV学习(4.15) 基于 GrabCut 算法的交互式前景提取

1. 目标 在这一章当中 我们将看到 GrabCut 算法来提取图像中的前景我们将为此创建一个交互式应用程序。 2. 理论 GrabCut 算法由英国剑桥微软研究院 Carsten Rother&#xff0c;Vladimir Kolmogorov和Andrew Blake发明&#xff0c;并在他们的论文“GrabCut”&#xff1a;使…

LLM之RAG实战(四十)| 使用LangChain SQL Agent和MySQL搭建多层RAG ChatBot

在传统的意义上&#xff0c;RAG 主要是从文档中检索用户想要的数据&#xff0c;从而提高大模型的能力&#xff0c;减少幻觉问题。今天&#xff0c;我们从另一个维度介绍RAG&#xff0c;RAG不从文档中获取数据&#xff0c;而是从MySQL数据库检索数据。我们可以使用LangChain SQL…

Vue40-vueComponent构造函数

一、组件的本质&#xff1a;VueComponent构造函数 组件的本质是&#xff1a;构造函数 二、每一次调用vue.extend&#xff0c;返回的事一个全新的 VueComponent VueComponent的源码如下&#xff1a; 三、组件中的this 组件中的this是VueComponent实例对象&#xff0c;结构和vm…

如果给电商系统颜值搞排名,我觉得淘宝千牛系统是天花板了。

淘宝的商家操作界面-千牛系统经过多年的迭代&#xff0c;无论从颜值上、功能上还是用户体验上都是行业天花板的存在&#xff0c;我截图软件上的一些图给大家分享下。

网络编程之XDP和TC

一、TC之于XDP 在前面分析过XDP&#xff0c;今天简单分析一下与其相关的TC&#xff0c;即traffic control,流量控制。在分析XDP时知道其只能用于ingress方向触发&#xff0c;而TC却可以在两个方向即ingress和egress方向触发。也可以简单理解成它可以同时钩住进出两个方向的数据…

foxmai邮箱使用技巧图文板简单容易,服务器配置密钥配置

本人详解 作者&#xff1a;王文峰&#xff0c;参加过 CSDN 2020年度博客之星&#xff0c;《Java王大师王天师》 公众号&#xff1a;JAVA开发王大师&#xff0c;专注于天道酬勤的 Java 开发问题中国国学、传统文化和代码爱好者的程序人生&#xff0c;期待你的关注和支持&#xf…

手把手教你实现条纹结构光三维重建(2)——条纹解码

在第一讲中&#xff0c;我们讲到了条纹的生成&#xff0c;这一讲&#xff0c;我们将实现条纹的解码。我们这里的解码技术很简单&#xff0c;即高低频倍数解码&#xff0c;详细的论文可以参考&#xff1a;《Temporal phase unwrapping algorithms for fringe projection profilo…

基于 Transformer 的大语言模型

语言建模作为语言模型&#xff08;LMs&#xff09;的基本功能&#xff0c;涉及对单词序列的建模以及预测后续单词的分布。 近年来&#xff0c;研究人员发现&#xff0c;扩大语言模型的规模不仅增强了它们的语言建模能力&#xff0c;而且还产生了处理传统NLP任务之外更复杂任务…

4-字符串-11-反转字符串-LeetCode344

4-字符串-11-反转字符串-LeetCode344 LeetCode: 题目序号344 更多内容欢迎关注我&#xff08;持续更新中&#xff0c;欢迎Star✨&#xff09; Github&#xff1a;CodeZeng1998/Java-Developer-Work-Note 技术公众号&#xff1a;CodeZeng1998&#xff08;纯纯技术文&#xff0…

认识一些分布函数-Frechet分布及其应用

1. 何为Frechet分布 Frechet分布也称为极值分布(EVD)类型II,用于对数据集中的最大值进行建模。它是四种常用极值分布之一。另外三种是古贝尔分布、威布尔分布和广义极值分布(Gumbel Distribution, the Weibull Distribution and the Generalized Extreme Value Distributi…

亿达中国武汉园区入选“武汉市科技金融工作站”及“武汉市线下首贷服务站”

近日&#xff0c;武汉市2024科技金融早春行活动在深交所湖北资本市场培育基地举行。会上&#xff0c;第四批武汉市科技金融工作站试点单位名单及第五批武汉地区金融系统线下首贷服务站名单正式公布&#xff0c;武汉软件新城成功入选上述两个名单。 为缓解科技型企业融资难题&a…

vue2+echarts实现简易的2d地图效果

背景 公司的一个可视化数据大屏里面&#xff0c;有一个使用echarts实现的2d地图。不是我开发的&#xff0c;在此记录一下实现过程以及一些扩展解构。应该是从哪个航空航线图改动了一下&#xff0c;效果看起来还是可以的。 效果预览 版本 vue版本使用的是"^2.6.12"…

我要成为算法高手-双指针篇

目录 什么是双指针?问题1&#xff1a;移动零问题2&#xff1a;复写零问题3&#xff1a;快乐数问题4&#xff1a;盛最多水的容器问题5&#xff1a;有效三角形个数问题6&#xff1a;查找总价格和为目标值的两个商品(两数之和)问题7&#xff1a;三数之和问题8&#xff1a;四数之和…

私域流量新利器:大模型+智慧客服+知识智能多管齐下,效果倍增!

前言 随着互联网环境的发展&#xff0c;线上市场竞争日益激烈&#xff0c;越来越多的企业开始关注私域流量的运营和管理——将品牌的用户数据在品牌官网、微信公众号、APP等自有平台上进行管理和运营&#xff0c;通过与用户建立深入的关系和互动&#xff0c;提升用户黏性、增强…

LNMP搭建:Linux+Nginx+MySQL+PHP

关闭防火墙和核心防护&#xff0c;使用一台机器Node1搭建LNMP systemctl stop firewalld; setenforce 0 所需源码包&#xff1a;可以去官网下载 编译Nginx 创建/data&#xff0c;在/data/下放源码包 [rootNode1 ~]#:mkdir /data;cd /data 安装依赖包 [rootNode1 data]#:yum …