LINUX入门篇【5】----程序的翻译过程解析

前言:

在C语言阶段我们已经讲过程序的翻译过程,我们知道程序是由预处理,编译,汇编,链接四部分组成的,但是,当时受到C语言编译器的限制,我们没法去深刻体会这个过程,所以,本次我们利用LINUX再一次更为详细的展现一下程序的翻译。

1.编译器:

不同的语言需要由不同的编译器来进行编译,我们一般使用gcc来编译C语言,g++来编译C++语言,且这个对应是不能混淆的,否则编译是无法通过的。
在这里补充一下C++文件的几种格式:.cpp,.cc,.cxx等,我们不能仅仅认识cpp后缀的叫C++文件,要知道C++后缀的文件不只一种
在LINUX中gcc是自带的,想要编译C++语言,需要我们下载一个g++编译器,在这里我们可以使用:
yum install gcc-c++,也就是利用我们上节课讲的yum软件搜索系统来下载
但是,说到这里,你或许会问,LINUX不是不看后缀么?
这个之前我是说过的,LINUX的确是不看后缀的,但是编译工具是看后缀的,所以我们规范文件名和代码还是很有必要的

2.程序的翻译过程详解:

先让我们复习一下程序的翻译的过程:预处理,编译,汇编,链接,**每经过一个阶段,我们所写的程序就被处理为一个不同的形式,但它的趋势是逐渐处理为我们看不懂而计算机硬件能看懂的过程。**这句话很关键,但为什么要这样去一步一步的去翻译呢?难道直接一步到位让计算机看懂不行么?
这就要谈一谈我们程序的发展过程了:
首先我们明白,计算机的本质是一堆硬件,只能处理二进制信息,不管是多么强大和先进的计算机,它都只能识别二进制的数据,因此,早期的科学家们使用打孔的方式打印计算机信息,后来经过发展,人们发明了一套编码负责专门处理这种二进制信息,这便是汇编语言,但是,就像我说过的,计算机只能看懂二进制信息,因此,需要专门把汇编语言翻译成二进制信息给计算机看,由此,便诞生了最早的编译器,汇编语言编译器,负责将汇编代码翻译成二进制语言交给计算机去理解。但是,即使是汇编语言依旧晦涩难懂,大部分人没法快速掌握语法和功能,由此,科学家们又以汇编语言为底层,开发出了更高级的语言—C语言!同时,C语言的编译器也应运而生,但和汇编编译器不同,C语言的编译器负责去将C语言的代码翻译成汇编语言,然后汇编语言再经过编译器变成二进制代码。从这之后,C++诞生了,但是其本质都不无承接C语言的做法,将其翻译成汇编语言。C/C++之后,又出现了一大批以C/C++为底层的解释性语言,JAVA python php他们的本质是解释代码的意思而不是编译,但是你可以理解为他们是将其代码解释成汇编代码,因此他们使用解释器而不是编译器。通过这个过程,我i们发现,语言的发展是一层接着一层去承接的,下一层把上一层当作底层来进行翻译,这个过程便是语言/编译器的自举过程。
在这里插入图片描述
这也就解释了为什么我们的计算机程序翻译是一步一步进行的而不是跨越,因为每一步都有对应的编译器,你总不能重新构建一个由C语言直接翻译为二进制代码的编译器吧,那样需要消耗大量的成本和时间,而且毫无意义,这样一层一层的编译,提高了效率也节省了成本。
由此,我们便先解开了为什么我们的计算机程序要一步一步去翻译的问题,下面就让我们一步一步去看:

1.预处理:

在预处理阶段,由C语言那篇文章我们知道,主要进行的是4个过程:
1.头文件展开
2.去掉注释
3.条件编译
4.宏替换

经过这4个过程,我们的程序代码就更加纯粹和简洁,我们以LINUX我写的这个代码为例子,来讲一讲。
在这里插入图片描述

这是一个很简单的C语言程序,在这里包括条件编译,宏,条件编译,注释,让我们看看经过预处理阶段后程序会变成什么样子呢?
我们wq退出程序,然后我们输入指令gcc -E 文件名 -o 新的文件名
这条指令的意思就是:从现在开始进行程序的翻译,到预处理完就停下来,并将预处理完的结果放入我们后面的文件中,如下:
在这里插入图片描述
我将文件放入到code.i文件中,现在让我们打开文件:
在这里插入图片描述
是的,你会发现宏被替换后消失了,同时条件编译直接保留条件编译要执行的程序部分,其他部分全部剪切掉,同时注释被取消,这样,我们的代码就变得更加简洁。
条件编译为我们提供了一个很好的思路:
通过条件编译,我们是可以实现代码的动态裁剪的,比如,就如同我们玩的游戏有时会有不同的版本切换,不同的版本或许只是几个数值上的改变,游戏的机制和操作方式没有任何区别,这种不同版本的维护,对应的源代码其实都是一份,而通过条件编译,就可以实现利用一份源代码去维护两个或者多个版本

2.编译:

下一个过程就是编译,即是将代码经过编译器编译成汇编语言,为下一步汇编进一步翻译成二进制码做准备,我们的指令为:
gcc -S code.i -o code.s
文件如下:
在这里插入图片描述
在这里便是汇编代码的内容,为下一步做准备

3.汇编:

指令如下:
gcc -c code.s -o code.o
在这里插入图片描述
到这里,已经变成能由计算机看懂的二进制代码了。

4.链接:

所谓的链接,其实本质上讲是我们的.o文件完成后,同系统库链接,从而最终形成可执行程序的过程。
链接还是很好理解的,不过在这里我们谈到了库,由此便让我们先讲一讲何为库:

1.动态库,静态库概念和理解:

我们现在所写的代码,包括一些可以直接使用的函数,都是前人写好的,我们都是直接拿来用。
那么,这些函数存储他们的库在哪里呢?我们可以用下面的指令来查看:
ldd +可执行程序文件如下:
在这里插入图片描述
我们的ldd指令就可以查看我们所写的可执行程序都链接了哪些库,在这里你会看见三个,由此我们先引入库的分类:

1.库的分类:

库主要分为两种:
1.动态库:
.库类别为.so的即为动态库,这是在LINUX,在windows中为xxxx.dll
2.静态库:
库类别为.a的即为静态库,这是在LINUX,在windows中为xxx.lib
而在我们的LINUX系统中,是基本不会默认安装静态库的,而是动态库居多,至于这是为什么,我们先把这条结论记住,之后等我们分析优缺点的时候,不用我说,你自然就知道原因了。

2.库命名:

一个常见的库的命名如下:
在这里插入图片描述
一个库的真正名字实际上就是去掉lib,类别,版本号剩下的,在这里就是C即为它的名字。

3.动静态链接的理解:

我们应该怎样理解链接呢?我用这样一张图去体现链接的过程,图片如下:
在这里插入图片描述
我们前面知道,LINUX系统中默认的库都是动态库,所以如果你删除了动态库,LINUX系统相当于直接用不了了,要重新装。
根据上面的图,我们来明确一下动静态库,动静态链接的概念:
动态库:是C/C++或者其他第三方提供的所有方法的集合,被所有程序以链接的方式关联起来。
动态链接:库中的所有函数,都有其对应的入口地址,所谓的动态链接,其实就是把链接的库中的函数的入口地址拷贝到我们的可执行程序的特定位置,方便程序执行时可以到对应地址的位置调用函数.(注意,由于程序没有实际执行,也就是说,程序没有实际上在内存空间中占用位置,故在这里我们的入口地址都是逻辑地址而非物理上的地址)
静态库:是C/C++或者其他第三方提供的所有方法的集合,被所有程序以拷贝的方式,将需要的代码拷贝到自己的可执行程序中。
静态链接:以拷贝的形式,直接把所需要的函数代码拷贝到程序当中

在这里,我们就很清楚动静态链接的差别所在了:动态链接是拷贝地址,而静态链接是拷贝代码,就像我上面的图所示的,静态相当于直接把代码放到自己的身边,而动态的代码依旧在原来的位置

4.动静态链接的优缺点:

动态链接:
优点:形成的可执行程序体积比较小,比较节省资源
缺点:由于涉及到根据地址调用的过程,因此要慢一些,并且强依赖动态库,一旦动态库没了,所有依赖这个库的程序都没法执行了
静态链接:
优点:即使库被销毁,由于程序代码已经被拷贝到程序中,因此可以独立运行
缺点:体积太大,浪费资源

由此,让我们想想我之前问大家的那个问题?为什么LINUX支持的都是默认的动态文件,而不是静态的呢?
这正是因为静态库占用了过大的空间,浪费了更多的资源,我们可以拿这样一个例子来说明:
我们在gcc指令后面加上-static,就代表静态链接的意思,如下我们产生了这样的情况:
在这里插入图片描述
在这里插入图片描述
你会发现,861288是静态链接的可执行程序的大小,而8360是动态链接的,即使是一个很小的程序,就有这样的大小差距,现在我想,默认动态库不是没有道理的吧。
补充,有时我们-static没法执行:这个时候需要我们安装C的静态:
sudo yum install glibc-static
如果你需要C++的静态编译器,你可以安装:
sudo yum install -y libstdc+±static

5.引发思考,一款合格开发环境应该为我们做什么:

在这里我必须重新提一下VS,它确实称得上是一款十分优秀的开发平台,随着我自己配置编译器的过程,我逐渐意识到vs的强大之处,我们在VS可以直接调用库,可以调试,可以重新编译和卸载上一次的编译结果,可以查看汇编代码。
那在我看来,一个优秀的开发环境应该具备:
1.配置好了各种开发需要的库环境,例如lib 等
2.设置了合适的查找路径,方便调用
3.规定好我们形成的可执行程序的链接方式

总结:

本篇,我们进一步查看了程序是如何被翻译出来的,以及库的链接是如何进行的,同时我们也清楚的知道,我们所写的程序是多种库组合出来的结果,没有这些库,我们的函数就需要自己去构造,很麻烦,库进一步帮助我们提高了开发效率,同时,也让我们对开发环境的配置要求有了一个初步大概的认识。之后,我们将进一步配置完善我们的代码编写vim工具,并且可以在LINUX上实现我们的第一个有趣的程序。

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

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

相关文章

软件研发团队适用的项目管理工具推荐

Zoho Projects是一款专为大型产研团队设计的项目管理工具,它也是许多软件开发行业高速成长背后的生产线。与其他项目管理产品相比,Zoho Projects最大的不同之处在于其独特的流程设计。在软件上线初期,Zoho Projects能够有效地帮助软件研发公司…

mac使用VMware Fusion安装Centos 7系统

mac主机芯片:Apple M2 Pro VMware-Fusion:13.5 centos:7 第一次操作: 按步骤选择操作系统 在选择虚拟启动虚拟机没有安装centos的界面 而是下图 改动:把UEFI换成BIOS ——>无果 第二次操作: 直接…

数据仓库工具箱-第三章-零售业务

文章目录 一、维度模型设计的4步过程1.1 第一步:选择业务过程1.2 第二步:声明粒度1.3 第三步:确定维度1.4 第四步:确定事实 二、零售业务案例研究2.1 第一步:选择业务过程2.2 第二步:声明粒度2.3 第三步&am…

5.浮点数及其运算

目录 一. 浮点数的表示 (1)表示 (2)规格化 二. IEEE 754标准 三. 浮点数的运算 (1)步骤 (2)关于舍入 四. C语言的强制类型转换 一. 浮点数的表示 (1&#xff09…

原型模式(创建型)

一、前言 原型模式是一种创建型设计模式,它允许在运行时通过克隆现有对象来创建新对象,而不是通过常规的构造函数创建。在原型模式中,一个原型对象可以克隆自身来创建新的对象,这个过程可以通过深度克隆或浅克隆来实现。简单说原型…

MySQL中UUID主键的优化

UUID(Universally Unique IDentifier 通用唯一标识符),是一种常用的唯一标识符,在MySQL中,可以利用函数uuid()来生产UUID。因为UUID可以唯一标识记录,因此有些场景可能会用来作为表的主键,但直接…

AIX5.3安装weblogic10.3

目录 1安装IBM JDK 1.6 2图形化准备 3安装weblogic 准备 4图形化界面安装 1安装IBM JDK 1.6 1.1检查操作系统 # oslevel 5.3.0.0 # bootinfo -y (显示AIX机器硬件是64位) 64 # bootinfo -K (显示AIX系统内核是64位) 64 因此,系统需要安装64位的jdk,…

使用非递归的方式实现归并排序

使用非递归的方式实现归并排序 话不多说,直接上代码: public class MergySort {public static void main(String[] args) {int[] nums {38, 27, 43, 3, 9, 82, 10};int[] sortedArray MergySort.mergySort(nums);// 输出排序后的数组for (int num : …

AIGC:使用bert_vits2实现栩栩如生的个性化语音克隆

1 VITS2模型 1.1 摘要 单阶段文本到语音模型最近被积极研究,其结果优于两阶段管道系统。以往的单阶段模型虽然取得了较大的进展,但在间歇性非自然性、计算效率、对音素转换依赖性强等方面仍有改进的空间。本文提出VITS2,一种单阶段的文本到…

如何构建并提高自己的核心竞争力?

上一篇文章聊到了软件工程师的核心竞争力主要分为三个方面:快速学习能力、解决问题能力和个人影响力,且核心竞争力的培养和提高需要长时间实践和积累,并不是短时间就可以达到的。这篇文章, 来聊聊如何培养和提高自己的核心竞争力。…

里氏代换原则

package com.jmj.principles.dmeo2.after;/*** 四边形接口*/ public interface Quadrilateral {double getLength();double getWidth();}package com.jmj.principles.dmeo2.after;/*** 长方形类*/ public class Rectangle implements Quadrilateral{private double length;priv…

windowCPU虚拟化已禁用解决方案

windowCPU虚拟化已禁用解决方案 1. 前言 window电脑要安装Docker或者VMware虚拟机就需要开启windows自身的虚拟化功能,除了在设置上要开启Hyper-V只要还需要开启CPU的虚拟化功能,而CPU的虚拟化则需要通过进入BIOS设置中开启 2. 检查是否开启了虚拟化功…

探索Linux世界:从基础到高级

标题 探索Linux世界:从基础到高级 🚀第一章:Linux入门篇第二章:掌握Linux基础命令第三章:文件操作的艺术第四章:征服vi/vim编辑器第五章:掌握Linux全部命令 文末赠书 博主 默语带您 Go to New W…

C# .NET Core API Controller以及辅助专案

准备工作 Windows 10Visual Studio 2019(2017就有可以集中发布到publish目录的功能了吧)C#将方法封装(据说可以提高效率,就像是我们用的dll那种感觉新增专案作为我们API的辅助专案(作用类似dll,此处,你也可以在你自己的API专案里建文件夹,但…

MCSM面板搭建教程和我的世界Paper服务器开服教程

雨云游戏云VPS服务器用Linux搭建MCSM面板和Minecraft Paper1.20.2服务器教程。 本教程演示安装的MC服是Paper 1.20.2版,其他版本也可以参考本教程,差别不大。 本教程使用Docker来运行mc服,可以方便切换不同Java版本,方便安装多个…

Ubuntu安装步骤

点击文件 --> 新建虚拟机: 找到第一章下载的ubuntu镜像文件,然后下一步 自定义名称和位置,然后下一步 根据需要定内存,2G以上即可: 单个文件即可 点击完成 回车,然后等待安装 回车 回车 回车 按上下键找…

QWidget 实现九宫格图案解锁

前言 最近需要实现一个九宫格图案解锁功能,查看网上的方案,基于QWidget的方案全网搜来搜去就一篇 Qt编写自定义控件:图案密码锁, 都是炒来炒去的同一篇,代码还比较复杂,运行后在PC端还是可以的,但是运行在arm机器上,就卡顿,或者容易断开手势连接线,各种不友好,于是自…

【python高级】asyncio 并发编程

【大家好,我是爱干饭的猿,本文重点介绍python高级篇的事件循环,task取消和协程嵌套、call_soon、call_later、call_at、 call_soon_threadsafe、asyncio模拟http请求、asyncio同步和通信、aiohttp实现高并发实践。 后续会继续分享其他重要知…

leetcode刷题 - SQL - 中等

1. 176. 第二高的薪水 筛选出第二大 查询并返回 Employee 表中第二高的薪水 。如果不存在第二高的薪水,查询应该返回 null(Pandas 则返回 None) 。查询结果如下例所示。 666中等的第一题就上强度 强行解法 select max(salary) as SecondHighestSalary from Emp…

多维详述MediaBox互动直播AUI Kit低代码开发方案

本专栏将分享阿里云视频云MediaBox系列技术文章,深度剖析音视频开发利器的技术架构、技术性能、开发能效和最佳实践,一起开启音视频的开发之旅。本文为MediaBox最佳实践篇,重点从互动直播AUI Kit的核心能力、技术架构、快速集成等方面&#x…