本文共 4684 字,大约阅读时间需要 15 分钟。
世界上第一台通用计算机-ENIAC即Electronic Numerical Integrator And Computer即电子数字积分计算机、(另说是ABC计算机),设计的初衷是军事相关, 由美国陆军资助、第一次测试用于计算氢弹项目。研发团队核心成员按是6个人、其中还有一个中国人:朱传榘。
埃达 洛夫莱斯, 英国数学家兼作家, 于1842年至1843年之间翻译一篇意大利军事工程师费德里克 路易吉阐述分析机的文章,但是没有表明是什么语言,估计类似于伪代码。
当电子计算机出来以后、第一门语言自然机器语言(二进制0和1、分别代表低电平和高电平)。
机器语言是面向硬件架构(CPU架构的)、不同的CPU架构会对应各自的一套指令集, 这个指令集最原始的就是机器语言。
指令集中的操作码、比如一个加法操作、由于硬件电路的实现不同、可能在A机器中、指令寄存器写入01(比如)就能实现加法操作、但是在B机器中国、指令寄存器中写入10能实现加法操作,(0和1在电路中分别代表低电平和高电平), 所以不同的CPU架构往往有不同的指令集。比如X86架构和ARM架构。
X86: Intel公司用于开发CPU的指令集架构、最早的就是Intel 8086 CPU, 为什么叫X86呢?因为该系列的处理器命名的最后两个数字都是86、比如Intel 8086、Intel 80186。X86-64指的是64位的X86架构的处理器、64位指的就是寄存器的位数是64位。
ARM架构: (Advanced RISC(Reduced Introduction Set Computing) Machine)是高级精简指令集机器、被广泛地用于嵌入式系统设计、手机处理器基于都是ARM架构的、节能。
汇编语言对应着不同机器语言指令集、特定的一种汇编语言和其特定的机器语言指令集是一一对应的。(这里的机器指的就是硬件架构、主要指的就是CPU架构、与内存以及外部存储设备关系不大)
机器语言可阅读性差、编程也不方便、 继而用英文单词来代替指令,仍然是面向机器的语言, 也就是不同的硬件平台会有不同的汇编语言。汇编语言需要使用编译器将汇编语言源程序翻译为机器代码。
汇编语言不仅面向语言、还面向厂家、因为汇编语言说到底是个助记符、不同的厂家可以指定不同的标准、即使是对于同一个CPU架构、比如X86、不同的厂家也会用各自标准的汇编语言、比如Intel(美国英特尔公司)语法指定的指令"mov al, 30h" 与AT&T(美国电话电报公司)汇编语法的:"movb $0x30, %al", 经各自的汇编器汇编后生成的十六进制机器代码都是"B0 30"。
如果一家公司制定自己的汇编语言、也有开发对应的汇编器将汇编语言翻译为在对应CPU架构上能够运行的二进制代码。汇编语言的作用仅仅是助记。
汇编语言有可移植性吗?没有。所谓可移植性指的是源代码不需要修改或者仅仅只需要做一些小的修改经过对应平台的编译器编译成机器代码后即可在对应机器上运行。为啥没有的, 因为不同的CPU架构指令集都不一样, 比如X86上有的指令 ARM架构没有、一个指令往往用一个英文单词表示、那ARM架构的电路设计都不支持这个指令、怎么去汇编这个汇编指令呢??
C语言是具备可移植性、请注意可移植性和跨平台的区别. 可移植指的是源代码不需要修改、但是要想在不同的平台上运行、必须在对应平台上重新编译后,方可在对应平台上运行。而跨平台性指的是源代码编译后的可执行文件放在任意平台都可以直接运行、而不要重新编译。JAVA就是跨平台语言、JAVA的跨平台性在于Java虚拟机在解释字节码文件时会根据运行平台的不同而做出对应平台的执行。
请注意 上文中所说的平台这个概念: 当没有操作系统出现的时候、程序员面对的平台就是赤裸裸地硬件平台, 比如X86的机器或者是ARM架构的机器、这时候程序员就是用对应硬件平台的机器语言指令集、再高级点、用对应机器语言指令集的汇编语言 + 汇编器进行编程, 此时程序员就叫硬件程序员, 直接和硬件打交道。但是一旦操作系统出现以后,(这里的操作系统指的是由高级语言C或者是C++写的), 除了写与硬件交互代码的程序员以外、一般的程序员不再需要和硬件打交道、而是与操作系统这个软件平台打交道。
操作系统的编写团队为了其他程序员可以在该系统上开发应用、那么便会提供该操作系统对应的SDK, 比如在Mac下就会提供Mac SDK,
/usr目录比较重要、/usr 全称: unix software resources: bin目录是可执行文件、include目录是头文件目录、lib目录是头文件中声明的函数的具体实现代码、后缀是.dylib, 动态链接库、是已经编译好的、使用编译器编译C程序时、在最后链接阶段、链接一下就好了。
可移植性: 所谓可移植性指的是源代码不需要修改或者仅仅只需要做一些小的修改经过对应平台的编译器编译成机器代码后即可在对应机器上运行。低级语言一般来说可移植性都很差、而高级语言一般都具备可移植性。根据我们上文的描述、可移植性指的是可以源程序不做修改的情况下、在对应的平台、有了操作系统后、就指的是操作系统平台, 编译后、程序即可运行。
C语言为何可移植呢?答案就是C标准库的存在。但是程序中针对特殊硬件设备、(如: 显示监视器、或者操作系统的特殊功能,通常是不可移植的.
....
不知道之前还有些啥语言、就列举些有名的。
IBM研发、高级语言, Fortran语言是为了满足数值计算的需求而发展出来的, 这门语言提出者约翰 巴克斯, IBM董事长统一,但是当时作为IBM顾问的冯诺依曼却反对, 反对理由:不切实际且没有必要。这门语言从1953年提出直到1957年才推出第一版。
通用的程序设计语言、由贝尔实验室的计算机科学家 肯 汤普森 设计、初衷是想在UNIX上开发一个Fortran编译器。
注:贝尔实验室, 隶属于AT&T(美国电话电报公司)、由电话之父 亚历山大 格拉汉姆 贝尔于1877年成立。
1971年, 由UNIX的开发者肯 汤普逊和丹尼斯 里奇发明。
为什么要用C语言写UNIX呢?为了UNIX系统的可移植性。
前身是Multics(多任务信息与计算系统)、分时多任务、贝尔实验室、麻省理工学院、美国通用电器公司共同参与研发, 1969年由于研发进度过慢、最终被裁撤、贝尔实验室退出。参与人员中有两个后来开发UNIX的肯 汤普逊和丹尼斯 里奇。
1969年, 肯 汤普森提议了UNIX, 同时开发了shell、shell不属于操作系统内核、它是用来和用户进行交互。它将命令传递给内核执行。第一版的UNIX称为UNICS, 主要是使用PDP-7汇编语言编写的, (PDP-7是一种小型计算机), 一些语言是由B语言和汇编语言混合编写的。1971年,肯 汤普森和丹尼斯 里奇研发了C语言、1973年两人使用C语言重写了UNIX, 形成了第三版的UNIX, 为了实现最高的效率、系统程序都是由汇编语言编写。
UNIX并不是个开源项目, 在UNIX出现后的10年间、UNIX在学术机构和大型企业中得到了广泛的应用、当时UNIX的拥有者AT&T公司以低廉的价格甚至免费的许可将Unix的源码授权给学术机构做研究或者教学之用。BSD(伯克利版本的UNIX)在UNIX的历史发展中具有很大的影响力,被很多商业厂家采用。称为很多商用UNIX的基础。其不断增加的影响力引起了原拥有者AT&T公司的注意, 开始了一场持久的著作权官司。后来把UNIX卖给了Novell。Novell允许伯克利分校自由地发布自己的UNIX变种、但是必须把来源于AT&T的代码删除、于是诞生了BSD Lite版。BSD是自由版本UNIX的基础。BSD 演化出了: FreeBSD、OpenBSD和NetBSD。
发明人:William Nelson Joy, 1970年(16岁)在伯克利加州大学上学期间开创了BSD, 他后来还发明了vim编辑器,后来他加入了Sun公司。
编写者:Linus Torvalds
库函数:
库函数分为两类:
1、C标准库函数ANSI C、
2、编译器特定的库函数
由于版权原因:库函数的源代码一般是不可见的。但是在头文件中你可以看到它对外接口库函数简介。
函数库: 操作系统建立的具有一定功能的函数的集合。库中存放函数的名称和目标代码, 以及连接过程中所需要的重定位信息,用户也可以根据自己的需要建立自己的用户函数库。
学着建立自己的用户函数库。
库函数:
存放在函数库中的函数、库函数具有明确的功能、入口调用参数和返回值、
连接程序: 将编译程序生成的目标文件连接在一起生成一个可执行文件。
头文件: 有时候也称为包含文件、C语言库函数和用户程序之间进行信息通信时要使用的数据和变量,在使用某一库函数时,都要在函数中嵌入(用#include)该函数对应的头文件。
库函数和系统调用的区别
库函数是语言或者应用程序的一部分、属于语言的一部分;而系统调用是内核提供给应用程序的接口、属于操作系统的一部分
库函数在用户地址空间执行, 系统调用是在内核地址空间执行。库函数开销较小、系统调用开销较大。
库函数是有缓冲的, 系统调用是无缓冲的。
系统调用依赖于操作系统平台、库函数并不依赖。
如何陷入内核:1、系统调用 2、中断 3、异常
后缀为.S 汇编语言
API/POSIX/C库
应用程序通过应用程序接口(API)而不是直接使用系统调用来编程。因为应用程序使用的这种编程接口实际上并不需要和内核提供的系统调用一一对应。
在UNIX中, 最流行的应用编程接口是基于POSIX标准的。其目标是提供一套大体上基于UNIX的可移植操作系统标准。
C库实现了UNIX系统的主要API、包括C标准库函数、和系统调用。
相反、内核只跟系统调用打交道、库函数、
Linux中每个调用都有相应的系统调用号作为唯一的标识,内核维护一张系统调用表。sys_call_table, 表中的元素是系统调用函数的起始地址, 而系统调用号就是系统调用在调用表的偏移量。在x86上, 系统调用号是通过eax寄存器传递给内核的。比如fork()函数的实现。所以、应用程序应该以某种方式通知系统、告诉内核自己需要执行一个系统调用、希望系统切换到内核态、这样内核就可以代表应用程序来执行系统调用了。
通知内核的机制是由软件实现的。首先、用户程序为系统调用设置参数、其中一个参数是系统调用编号。参数设置完后、程序执行“系统调用"指令。 x86系统上的软件中断由int80H 产生。这个指令会导致一个异常: 产生一个事件、这个事件会导致处理器切换到内核态并跳转到一个新的地址、并开始执行那里的异常处理程序, 并开始执行那里的异常程序。此时的异常处理程序实际上就是系统调用处理程序。它与硬件体系结构紧密相关。
系统调用对应一个内核函数。
arch/x86/syscalls/syscall_64.tbl
转载地址:http://rnzji.baihongyu.com/