类别:
慕文20****90

1月前

后端开发/Java

就是看机关考试结果 --

富士康的价格快速健康g

0

0

0

0

lamansun

1月前

后端开发/.Net Core

编程语言深入浅出 --

### 前言

本系列文章是关于当前主流编程语言深入浅出的学习教程。这些年自己在学习编程语言和项目开发的过程中经常会遇到各种问题,发现很多问题产生的原因是自己对编程语言理解不够深入,只是掌握了语言的基本语法。市面上学习编程语言的书籍或视频教程很多也都停留在语法的讲解中,很少提及编程语言的底层设计逻辑,如果对编程语言没有深入的了解,编程能力也容易停滞不前。所以我打算对主流编程语言做一次系统的梳理和学习,深入理解各种编程语言设计的精髓,以及在写代码的过程中应该如何避开编程语言中的坑,写出简洁规范的代码。


#### 编程语言的进化史为了更好的理解编程语言,我们先对编程语言的发展做个大概的了解。
![编程语言的进化史](/imgs/1-1.png)(图1-1)
##### 1.机器语言机器语言是机器能直接识别的程序语言或指令代码,无需经过翻译,每一操作码在计算机内部都有相应的电路来完成它,或指不经翻译即可为机器直接理解和接受的程序语言或指令代码。机器语言编出的程序全是些0和1的指令代码,直观性差,还容易出错。除了计算机生产厂家的专业人员外,绝大多数的程序员已经不再去学习机器语言了。
##### 2.汇编语言不难看出机器语言作为一种编程语言,编写和可阅读性很差,所以人们对机器语言进行了升级和改进,用一些容易理解和记忆的字母,单词来代替一个特定的指令。这种语言就是我们所说的汇编语言,即第二代计算机语言。但计算机的硬件不认识字母符号,所以汇编语言编写后需要把这些字符翻译成计算机能够识别的二进制指令,专门做这种翻译工作的软件我们称作编译器。
##### 3.高级语言虽然汇编语言让计算机指令变得更容易编写和阅读,但汇编语言与人类语言的逻辑思维方式差异很大,学习和使用汇编语言还是非常困难。而且不同硬件的指令可能也存在差异,在使用汇编语言的时候还需要针对这些指令上的差异编写不同的代码。为了解决这些问题,所以发展出了第三代编程语言,我们也称为“高级语言”。早期的高级语言有C语言、Basic和Pascal等,这些语言都是“面向过程”的语言。在20世纪80年代又产生了另外一种编

程思想,即“面向对象”编程,如C++、JAVA、C#、Swift等。以上这些语言都需要经过“编译”后再被计算机执行,但还有一类语言是在执行的时候才被“编译”的,比如我们现在常见的Javascript、Python、Lua等脚本语言。后面我们还会对这几类编程语言的产生和发展再做深入的了解。
![高级语言-汇编语言-机器语言](/imgs/1-2.jpg)(图1-2)上图是一段C语言、汇编语言和机器语言的展示(机器语言是通过十六进制展示的)
#### 编程的定义我们常说“程序设计=数据结构+算法”。在我的理解中,数据结构就是对数据的组织,算法就是对数据进行加工处理。我们要实现某个程序功能,解决某个问题,都可以转化为组织数据和处理数据。对数据的组织能力可以决定一个程序员的架构设计能力,所以我们在学习编程的过程中,应该多注意“数据结构”,一般的程序也用不到太复杂的“算法”。以前经常有人问我,学编程是否需要数学特别好,是否需要学历高才能学好。我的回答是,兴趣才是学好编程的主要条件,因为绝大多数编程工作所用到的数学知识是很少的。当然,良好的数学知识对职业发展还是有帮助的,比如图形图像学、人工智能、大数据等工作就需要具备很强的数学知识,学这些方向也能获得更高薪的工作。
#### 计算机数据的表现形式我们知道了“数据”在编程中的重要性,那么各种数据在计算机中都是什么样的呢?其实不管是什么数据,在计算机中都是0和1的存在,因为计算机只能处理二进制。虽然只有0和1两个数,但可以组合出无穷的数据。我们生活中常用的数据类型可以大体分为数字、文字、图像、视频等,那么我们来看看用0和1怎么来表示这些数据。
##### 1.整数我们知道阿拉伯数字是十进制的,也就是有0-9共10个数字,当表示的数字比较大的时候我们只需要遇十进位就行。同理,二进制只用0和1两个数字,遇二进位。在编程中我们还经常使用八进制和十六进制,八进制使用0-7来表示,十六进制使用0-9和字母A-F来表示。不同进制之间是可以互相转换的,我们通常把内存中的二进制数据转换成十六进制的方式来查看,因为十六进制让数据展现得更紧凑易看。如图1-2展示机器语言的部分。
![不同进制数字](/imgs/1-3.png)(图1-3)上图展示了不同进制的数字表示形式
这里我们需要插入一个话题,聊一下“内存”。我们的程序和各种文件都存储在硬盘或其他存储器中,当运行的时候按需加载到内存里面。内存断电就丢失所有的数据,程序指令和数据都是临时存放在内存中(内存的大小决定了计算机能同时运行多少程序不会卡顿)。程序执行的时候就把内存中的一条条指令和数据发送给CPU,然后又把CPU处理后的数据写进内存里面。
![硬盘-内存-CPU](/imgs/1-4.png)(图1-4)
我们可以把内存想象成一个巨大的网格表,每个格里面可以放入0或1(默认每个格里面初始都是0),然后我们给每个网格一个编号(从0开始),这样我们通过编号就能找到想要的数据,这个寻找的过程我们称为“寻址”。
![内存示意图](/imgs/1-5.png)(图1-5)
这里我们就需要思考一个问题,我们是通过数据的起始位置的编号找到这个数据存放位置的,那应该怎么来确定读取出多少长度的数据才是我们想要的呢?可能你会想到我们给数据增加一个长度标记,比如我们存了一个数字5在内存中,二进制是101,那么我们在寻址的时候就告诉程序我们只读出3个长度格子的数据。这样看似解决了问题,但同时也导致了一个巨大的问题,因为很多时候我们还需要对存储的数值进行修改,如果我们把5改成12(二进制就是101改成了1100),这样需要用来存储的内存长度增加了,这个时候如果直接写入会导致覆盖其它数据,我们就只能在空内存块去存储这个数值,这样也就导致现在存放101的内存块浪费了。
其实在编程语言中是这样解决这个问题的,我们对所有数据类型规定一个固定的内存占用长度。比如整数,我们一般称作int类型(单词integer的缩写,称为整型),它使用32个内存格的长度来存放,既然有固定的长度,那么存放的数值大小肯定是有上限的,用第一格来代表是正整数还是负整数,剩余31格可以存下的数值最大就是2的31次方,所以int类型的数据可以存放-2147483648至2147483647。
![整型在内存中的示意图](/imgs/1-6.png)(图1-6)
你应该发现了,为什么-5在内存中不是10000000000000000000000000000101呢?这里我们就需要了解下CPU的计算原理,CPU不能做减法运算,只能做加法运算,所以负数在内存中用“补码+1”的方式存储,这样就可以把减法运算变成加法运算。我们这里拿十进制的减法运算举例,比如我们做1位数的减法5-3,我们可以转变成5加上7(十进制下,0的补码是9,1的补码是8,2的补码是7,3的补码是6,得到补码之后还需要加1),就是5+6+1=12,保留1位就得到了正确结果2。再举例2位数的减法45-22,22的补码是77,可以转变成45+77+1=123,保留2位数结果就是23。二进制下0的补码是1,1的补码是0,所以只需要把0和1对换后加1就行了。所以-5的补码最后三位就是101的补码010再加1,所以是011。这也是为什么int类型的数据可以存放的数值范围是-2147483648至2147483647,负数要大1。
在某些情况下我们不需要存储负值,所以在编程语言中还定义了uint类型(无符号整型),它的存值范围是0-4294967295。当然也许我们存储的数值可能超过这个范围,也可能只需要存储很小的值,所以编程语言中一般还定义了一些类型供使用,下图整理把常见的整数类型做了一个归纳。
![整数型归纳](/imgs/1-7.png)(图1-7)
> 前面我所说的“内存格”其实在计算机专业术语叫做“位”(英文bit),我们把8位的长度称作1个“字节”(byte)长度,所以上面所说的数据类型可以这样表述,int是32位数据类型(占用4个字节),long是64位数据类型(占用8个字节),其他类型不再赘述。我相信你经常听说32位操作系统,64位操作系统,软件也分32位版本,64位版本,其实这个长度是指内存寻址的长度。前面说了计算机对每个内存地址都有编号,程序在运行的时候也需要存储各个数据在内存中的编号,这个编号就是一个正整数,存放这个编号的长度就代表了应用程序是32位还是64位(操作系统也是一个应用程序,道理一样)。那么这个长度有什么影响呢?前面说了32位无符号正整数可以表示的最大数值4294967295,刚好就是4GB大小(4GB=4096MB=4194304KB=4294967296bit),所以32位的程序只能使用4GB内存,一般情况下4GB内存足够了,但对于某些大型应用来说还是不够。如果你安装一个32位的windows操作系统,你会发现不管你安装了多大的内存,操作系统中显示可用内存只有3G多(不足4G的原因是操作系统导致的)。所以为了使用更多的内存,现代操作系统都向64位转变了。这里再说个比较有意思的,你应该知道ip地址是4段0-255的数字组成,这个也并不是偶然的,因为一个0-255的数字刚好占用一个字节长度(8bit),4个就刚好占用32位。所以计算机里面很多现象都可以站在数据的角度去思考。
##### 2.小数前面说了整数,我们再来说说小数(计算机中称为浮点数)在内存中是怎么存储的。浮点数一般分两种类型:float类型(单精度浮点数,长度32位)、double类型(双精度浮点数,长度64位)。先来了解一个数学概论,小数都可以转变成一个尾数(整数)和指数的方式表示,比如63.456可以表示成63456x10^-3^,所以我们在存储一个小数的时候可以分三部分存储:符号(正或者负),指数,尾数。
![浮点数](/imgs/1-8.png)(图1-8)
##### 3.文字文字是通过把字符与数字意义对应的方式编码后存储的,早期计算机只支持英文字符,编码方式是ASCII编码,如下图:
![ASCII编码](/imgs/1-9.jpg)(图1-8)
ASCII编码一共定义了128个字符,包括了阿拉伯数字、英文字母、标点符号、输入控制符(换行,回车,删除,退格等)等。128个字符的编码可以通过一个字节(byte)存储下,所以这也是为什么把8位(bit)称做一个字节(byte)吧。随着计算机在各个国家的普及,计算机科学家制定了全球统一的Unicode编码,使用2个字节(可以编码65536个常用字符)或4个字节(比如不常用的繁体字)来存储一个字符,满足了不同语言文字的编码。常见的还有一种编码UTF-8,这个是针对Unicode的一种可变长度字符编码,兼容ASCII编码,在网络领域使用广泛,如web,电子邮件等。关于编码的具体实现方式有兴趣可以查阅相关资料。
##### 4.图片
##### 5.音频
##### 6.视频
一张一张的图片按顺序显示出来就是一段动态的视频,所以一段视频就是一组图片通过编码和压缩后的产物。
从以上内容我们可以看出,所有数据和信息都可以通过数字编码后以二进制的方式存储在计算机中,这就是“数字化”。我们已经生活在了一个数字化的时代
#### 计算机硬件和操作系统常见的计算机硬件由运算器、控制器、存储器、输入设备和输出设备五部分组成。

0

0

0

0