我们听说过很多种编程语言,很多概念和叫法,很容易混淆,今天我们来分一下类。

1 与硬件的距离远近

可分为 低级语言 (Low-Level Programming Language) 和 高级语言 (High-Level Programming Language)。

1.1 区别

低级语言 高级语言
较难学习和理解 容易学习和理解
执行速度很快 需要翻译程序,所以比低级语言执行起来更慢
不允许抽象或只允许少许抽象 运行很多抽象
非常贴近硬件,在硬件层面编程有很多帮助工具 在硬件层面没有提供很多工具
在编程过程中,硬件知识是必须的 在编程过程中,硬件知识并不是必须的
修改程序很困难 很容易修改程序
声明语句可以直接对应到处理器指令 一条声明可能涉及执行多条处理器指令
包括机器语言和汇编语言 BASIC, Perl, Pascal, COBOL, Ruby, C, C++等

1.2 低级语言

1.2.1 机器语言(Machine Language)

是用 二进制代码 表示的 计算机能直接识别和执行的一种机器指令的集合。也被称为 二进制语言。机器语言的指令集由操作码和操作数两部分组成。操作码规定了指令的操作,是指令中的关键字,不能缺省。操作数表示该指令的操作对象。根据硬件指令集写 0101 ,当然一般都用八进制表示。机器语言写的程序存在不便于阅读、难以记忆的问题。

早期计算机就是指可以执行机器指令,进行运算的机器。在我们常用的PC机中,有一个芯片,就是我们常说的CPU(Central Processing Unit,中央处理单元)可以完成前面所说的计算机的功能,但是每一种这样的微处理器(CPU)由于硬件设计和内部结构的不同,就需要用不同的电平脉冲来控制,使它工作。所以每一种微处理器都有自己的机器指令集,也就是机器语言。

早期的程序设计均使用机器语言。程序员们将用0、1数字编成的程序代码 打在纸带或卡片上,1打孔,0不打孔,再将程序通过纸带机或卡片机输入计算机,进行运算。

用机器语言编写程序,编程人员要首先熟记所用计算机的全部指令代码和代码的涵义。手编程序时,程序员要自己去处理每条指令和每一数据的存储分配和输入输出,还要记住编程过程中每步所使用的工作单元处在何种状态。这是一件十分繁琐的工作,编写程序花费的时间往往是实际运行时间的几十倍或几百倍,而且,编出的程序全是些0和1的指令代码,直观性差,还容易出错。

那么该怎么办呢?这时候汇编语言便产生了。

需要注意的是现在除了计算机生产厂家的专业人员外,一般是不需要学习机器语言了。

1.2.2 汇编语言(Assembly Language)

是一种用于电子计算机、微处理器、微控制器,或其他可编程器件的低级语言。它用 助记符 代替机器指令的操作码,用 地址符号或标号 代替指令或操作数的地址。也被称为 符号语言。在不同的设备中,汇编语言对应着不同的机器语言指令集,通过 汇编过程 转换成 机器指令。汇编语言的主体是汇编指令,汇编语言是二进制指令的文本形式,特定的汇编语言 和 特定的机器语言指令集 是一一对应的,不同平台之间不可直接移植。它对硬件指令做了简单的封装,一些操作可以用 ADD,MOVE 等英文单词来表示了,比如,加法指令00000011写成汇编语言就是 ADD。

操作:寄存器bx的内容送到ax中

1000100111011000  机器指令

mov ax,bx         汇编指令 

我们能很明显的从上面两条指令看出区别,相对于机器指令而言,汇编指令是很容易记住的。

可能有人会问,我们用汇编语言编写程序,可是计算机只认识机器指令,那该怎么办?这时候就需要一个能将 汇编语言 翻译成 机器指令 的工具,我们称其为汇编器(有别于编译器)。程序员用汇编语言写出源代码,再用汇编器将其编译为机器码,最后由计算机执行。

汇编语言是直接面向处理器(Processor)的程序设计语言。处理器是在指令的控制下工作的,处理器可以识别的每一条指令称为机器指令。每一种处理器都有自己可以识别的一整套指令,称为指令集。处理器执行指令时,根据不同的指令采取不同的动作,完成不同的功能,既可以改变自己内部的工作状态,也能控制其它外围电路的工作状态。

汇编语言的另一个特点就是它的操作对象是寄存器或者存储器,也就是说它是直接和寄存器和存储器打交道,而不是具体的数据,这也是为什么汇编语言的执行速度要比其它高级语言快的原因。但同时这也使编程更加复杂,因为数据是存放在寄存器或存储器中,那么必然就存在着寻址方式,也就是用什么方法找到所需要的数据。例如上面的例子,我们就不能像高级语言一样直接使用数据,而是先要从相应的寄存器ax、bx 中把数据取出。这也就增加了编程的复杂性,因为在高级语言中寻址这部分工作是由编译系统来完成的,而在汇编语言中是由程序员自己来完成的,这无异增加了编程的复杂程度和程序的可读性。

再者,汇编语言指令是机器指令的一种符号表示,而不同类型的CPU 有不同的机器指令系统,也就有不同的汇编语言。因此,汇编语言程序与机器有着密切的关系。除了同系列、不同型号CPU 之间的汇编语言程序有一定程度的可移植性之外,不同类型(如:小型机和微机等)CPU 之间的汇编语言程序是无法移植的,也就是说,汇编语言程序的通用性和可移植性要比高级语言程序低。

1.3 高级语言

高级语言并不是指某种语言,而是包括很多种编程语言,比如Java、C、C++、C#、python等等,是高度封装的编程语言。高级语言与计算机的硬件结构和指令系统无关,它有更强的表达能力,可方便地表示数据的运算和程序的控制结构,能更好的描述各种算法,而且容易学习掌握。但高级语言编译生成的程序代码一般 比 用汇编程序语言设计的程序代码 要长,执行的速度也慢。

汇编语言和高级语言最后都要转换成机器语言,但是高级语言由于高度封装,相同的实现下,高级语言转换成机器语言的执行步数通常都比汇编语言多,这也是为什么高级语言一般都比汇编语言性能差的原因。

编程语言分类-LMLPHP

高级语言编译过程

这里的蓝色部分表示编译过程。需要注意:

  • 当源语言是C,C++等语言时,这里的中间代码指的是 汇编代码,目标代码是 机器代码;
  • 当源语言是.Net时,这里的中间代码就是 MSIL中间码,保存在 .dll文件中,最后由 CLR 运行;
  • 当源语言是Java时,这里的中间代码就是字节码,保存在.class类文件中,最后由 JVM 运行;
  • 还有很多语言在运行前不需要编译,而是由解释器进行解释执行;

1.4 对比

编程语言分类-LMLPHP

机器语言、汇编语言、高级语言对比

2 执行前是否需要编译

2.1 编译型语言 Compiled Language

需通过编译器(Compiler)将源代码编译成机器码之后,才能执行的语言。一般需经过编译(compile)、链接(link)这两个步骤。

  • 编译是把源代码编译成机器码;
  • 链接是把各个模块的机器码和依赖库串连起来生成可执行文件;

优点

  • 编译器一般会有预编译的过程对代码进行优化。
  • 一次编译,多次执行,程序执行效率高。
  • 可以脱离语言环境独立运行。

缺点

  • 编译之后如果需要修改就需要整个模块重新编译。
  • 编译时需根据运行环境平台选择不同的编译器,不同的平台之间移植就会有问题,需编译不同的可执行文件。

代表语言:C、C++、Pascal、Object-C以及最近很火的苹果新语言swift

例如 C、C++等语言,写好之后,通过 编译器 编译成二进制文件,就可以在 CPU 上执行了。运行的时候不需要依赖于其他软件,所以一般执行效率高。

2.2 解释型语言 Interpreted Language

使用专门的解释器 对源程序 逐行动态解释成特定平台的机器码并立即执行。解释型语言 有时候也被叫做 脚本语言 (Scripting Language)。

优点

  • 有良好的平台兼容性,在任何环境中都可以运行,前提是安装了解释器(虚拟机)。
  • 灵活,修改代码的时候直接修改就可以,可以快速部署,不用停机维护。

缺点

  • 每次运行的时候都要解释一遍,性能上不如编译型语言。

代表语言:JavaScript、Python、Erlang、PHP、Perl、Ruby

2.3  混合型语言

既然编译型和解释型各有缺点,就有人想到把两种类型整合起来,取其精华去其糟粕,于是就出现了混合型语言。

  • C# 在编译后生成 MSIL中间码(MicroSoft Intermediate Language) 而不是机器码,保存在dll文件中。.Net 平台提供了 通用语言运行库(CLR:Common Language Runtime,类似于Java虚拟机) 来运行中间码首次运行时由 JIT 编译成 机器码 并缓存在内存中,下次运行时直接从内存中读取执行。
  • Java 在执行前先编译成 字节码 (bytecode) .class文件,在执行时,Java虚拟机(JVM)读取字节码,进行 解释执行。
  • Python文件如果加载了其他模块,例如import urllib2,那么python会对urllib2.py进行 编译成字节码,生成urllib2.pyc,在执行时,Python虚拟机(PVM)读取字节码,进行解释执行。

严格来说,混合型语言属于解释型语言,而 C#稍微偏向于 编译型语言。

2.4 区别

编译型语言就像餐馆里点了很多菜,一次做完并打好包,至于你在什么时候吃,在哪里吃,都可以。

解释性语言就像在火锅店里点了一个火锅和很多配菜,一边上菜,一边下锅,一边吃。

混合型语言则像是在火锅店里下单打包好了,回家再一边下锅,一边吃。

3 运行时可否改变代码结构

3.1 动态语言

是一类在运行时可以改变其代码结构的语言:例如引入新的函数、对象、甚至代码,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。

主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang。

3.2 静态语言

与动态语言相对应的,运行时结构不可变的语言就是静态语言。如Java、C、C++。

3.3 注意

很多人认为解释型语言都是动态语言,这个观点是错的!Java是解释型语言但是不是动态语言,Java不能在运行的时候改变自己结构。

反之成立吗?动态语言都是解释型语言。也是错的!Object-C是编译型语言,但是他是动态语言,得益于它特有的run time机制(准确说run time不是语法特性是运行时环境,这里不展开)OC代码是可以在运行的时候插入、替换方法的。

C#是偏编译型语言,但也是动态语言,通过C#的反射机制可以动态的插入一段代码执行。

4 数据类型是否在运行前确定

4.1 动态类型语言

动态类型语言的 数据类型 不是在编译阶段决定的,而是把 类型绑定 延后到了运行阶段。

主要语言:Python、Ruby、Erlang、JavaScript、Swift、PHP、Perl。

注意:动态类型语言 和 动态语言 是完全不同的两个概念,两者要注意区分:

  • 动态类型语言 是指在运行期间才去做 数据类型检查 的语言,针对的是数据类型;
  • 动态语言 是指 运行时 可以改变代码结构 的语言,针对的是代码结构;

4.2 静态类型语言

静态语言的数据类型在 编译期间 或者 运行之前 是确定的,在编写代码时要明确变量的数据类型。

主要语言:C、C++、C#、Java、Object-C。

4.3 注意

很多人认为解释型语言都是动态类型语言,编译型语言都是静态类型语言,这个是错的。Swift是编译型语言但是它也是动态类型语言。C#和Java是解释型语言也是静态类型语言。

 

5 变量的数据类型是否容易转换

5.1 强类型语言

一旦一个变量被指定了某个数据类型,如果不经过强制类型转换,那么它就永远是这个数据类型。你不能把一个整形变量当成一个字符串来处理。

主要语言:Java、C#、Python、Object-C、Ruby

5.2 弱类型语言

数据类型可以被忽略,一个变量可以赋不同数据类型的值。一旦给一个整型变量a赋一个字符串值,那么a就变成字符类型。

主要语言:JavaScript、PHP、C、C++(C和C++有争议,但是确实可以给一个字符变量赋整形值,可能初衷是强类型,形态上接近弱类型)

5.3 注意

一般来说,动态类型语言是弱类型语言,静态类型语言是强类型语言,但两者没有必然的决定关系。例如 Python是动态类型语言,却是强类型语言。

6 其他

  • 按照程序语言设计风格可分为 命令式语言(过程化语言)、结构化语言、面向对象语言、函数式语言、脚本语言等;
  • 按照语言应用领域可分为通用程序语言(GPPL)和专用程序语言(DSL);
04-16 21:57