《深入理解计算机系统》(一)

只有ASCII字符组成的文件称为文本文件。其他文件则称为二进制文件。

#include<stdio.h>

.............


        hello.c的表示方法说明了一个基本思想:系统中所有的信息——包括磁盘文件、储存器中的程序、存储器中存放的用户数据以及网络上传送的数据,都是由一串比特表示的,区分不同数据对象的唯一方法是我们读到这些数据对象时的上下文。比如在不同的上下文中,同样的字节序列可能表示一个整数、浮点数、字符串或者机器指令。

             C与Unix操作系统相关密切,C从开始就是作为一种用于Unix系统的程序语言开发出来的,Unix内核的大部分,以及所有它支持的工具和函数库都是用c语言编写的。C是一个小而简单的语言。C语言的设计是由一个人而非一个协会掌控的,它的简单使它相对简单,也易于一直到不同的计算机上。C语言是系统级编程的首选,同事它也非常适用于应用级程序的编写,JAVA、C++、C#是类C语言

           为了在系统上运行C程序,每条C语句都必须被其他程序转化为一系列的低级机器语言指令,然后这些指令按照一种称为可执行目标程序(executable  object  program)的格式打好包,并以二进制磁盘文件的形式存放起来。

         在UNIX系统上,从源文件到目标文件的转化是由编译器驱动程序(compiler  driver)完成的,并且编译器驱动程序在这个翻译过程需要分为四个阶段完成的(预处理阶段、编译阶段、汇编阶段、连接阶段)

  预处理器(cpp)、编译器(ccl)、汇编器(as)

  一、    了解编译系统如何工作是大有益处的;

1、优化程序性能。(为了我们在C程序中做出好的代码选择我们确实需要对汇编语言以及编译器如何将不同的C语句转化为汇编语言有一些基本的了解)

2、理解连接时出现的错误。(一些最令人困扰的程序错误往往都与链接器操作有关,尤其是当你试图建立大型的软件系统时)

3、避免安全漏洞。(近年来,缓冲区溢出错误造成大多数网络和Internet服务器上的安全漏洞,这些而错误的存在时因为太多的程序员忽视了编译器用来为函数产生代码的堆栈规则)

二、处理器读并解释存储在存储器中的指令

总线:贯穿整个系统的是一组电子管道,称作总线,它携带信息文字并负责在各个部件间传递。通常总线被设计成传送定长的字节块,也就是字(word),字中的字节数(即字长)是一个额基本的系统参数,不同的系统中也不尽相同。

三、    I/O设备

   I/O(输入/输出)设备是系统与外界联系的通道,包括:作为用户输入的键盘和鼠标、作为用户输出的显示器、以及用于长期存储数据和程序的磁盘驱动器(即磁盘)

每个I/O设备都是通过一个控制器或适配器与I/O总线连接起来的。控制器和适配器之间的区别在于他们的组成方式。

  主存:是一个临时存储设备,在处理器执行程序时,它被用来存放数据和程序处理的数据。

 处理器:中央处理单元(CPU)简称处理器,是解释或执行存储在主存中指令的引擎。处理器的核心是一个被称为程序计数器(PC)的字长大小的存储设备(或寄存器)。在任何一个时间点上,PC都指向主存中的某条机器语言指令(内含其地址)




      执行hello程序

1、shell程序执行它的指令,等待我们的输入命令。当我们在键盘上输入字符串“/hello”后,shell程序就卓一读取字符到寄存器,再把它存放到寄存器中。

2、当我们在键盘上敲回车键时,shell就知道我们已经结束了命令的输入,然后shell执行一系列指令,这些指令将hello目标文件中的代码和数据从磁盘拷贝到主存,从而加载hello文件

DMA(直接存储器存取):数据可以不通过处理器而直接从磁盘到达内存

一旦hello目标文件中的代码和数据被加载到了存储器,处理器就开始执行hello程序的主程序中的机器语言指令。这些指令将“hello ,world”串中的字节从存储器中拷贝到寄存器文件,再从寄存器文件拷贝到显示设备,最终显示在屏幕上。

    四、高速缓存:就是系统花费了大量时间把信息从一个地方挪到了另一个地方。

根据机械原理,较大的存储设备要比较小的存储设备运行的慢,而快速设备的造价远高于低速同类设备,比如说,一个典型系统上的磁盘驱动器可能比主存大100倍,但是对处理器而言,从磁盘驱动器上读取一个字的时间开销要比从主存中读取的开销大1000万倍。类似地,一个典型的寄存器文件值存储几百字节的信息,于此相反主存里可存放几百万字节,然而处理器从寄存器文件中读取数据比从主存中读取要快几乎100倍。随着这些年半导体技术的进步,这种处理器与主存的之间的差距还在持续增大。加快处理器的运行速度要比加快主存的处理速度要容易和便宜的多。针对这种差异,系统设计者采用了更小更快的存储设备,称为高速缓冲存储器(高速缓冲)被用来作为暂时的集结区域。

五、形成层次结构的存储设备

在处理器和一个较大较慢的设备(例如主存)之间插一个更小、更快的存储设备(例如告诉缓存存储器)

存储器结构分层的主要思想是一个层次上的存储器作为下层次上的存储器的高速缓存。例如寄存器可以作为L1的高速缓冲,L1可以作为L2的高速缓冲,以此类推。

操作系统管理硬件例如:当shell加载和运行hello程序时,当hello程序输出自己的消息时,程序没有直接访问键盘、显示器、磁盘或者主存储器。取而代之的是他们依靠操作系统提供的服务。我们可以把操作系统看成是应用程序和硬件之间插入的一层软件,所有应用程序对硬件的操作尝试都必须通过操作系统

操作系统有两个基本功能:防止硬件被失控的应用程序滥用;在控制复杂而又通常广泛不同的低级硬件设备方面,为应用程序提供简单一致的方法。并且操作系统通过进程、虚拟存储器和文件实现这个两个功能。

六、进程是操作系统的一种抽象,在一个系统上可以同时运行多个进程,而每个进程都好像在独占地使用硬件我们称之为并发运行,实际上是说一个进程的指令和另一个进程的指令是交错执行的。实现这种交错执行的机制称为上下文切换(context  switching)。操作系统保存进程所需要的所有状态信息,这种状态就是上下文(context)

操作系统中对于不同的进程会设置不同的优先级
我们知道的进程在CPU上运行在宏观上是并行的而微观上是串行的,就是说任意一个时刻CPU上只有一个进程在运行,而每个进程只运行一个很短的时间片,所以才给人一个错觉:所有进程都同时在运行
这样的话,当多个进程同时需要运行时,就会对CPU进行资源争夺,所以进程之间需要排队,然后排队的方法有很多种,一般是先来后到式。然后对于一些紧急而重要的进程,后来却得不到应有的处理,所以我们给进程设置一个优先级,然后根据优先级设置进程占用CPU时的算法。
一般的算法都是按照时间上的先后,而对于一些高优先级的进程,可以优先运行。
     当操作系统决定从当前进程转移控制权到某个新进程时,就会进行上下文切换。即保存当前进程的上下文、恢复新进程的上下文,然后将控制权转移到新进程,新进程就会从它上次停止的地方开始

       由于不同的进程交错执行,打乱了时间的概念,使得程序员很难获得运行时间的准确和可重复测试

七、线程:尽管我们认为一个进程只有单一的控制流,但在现代系统中,一个进程实际上可以有多个称为线程的执行单元组成,每个线程都运行在进程的上下文中,并共享同样的代码和全局数据

       多线程之间比多进程之间更容易共享数据,线程一般都比进程更高效

虚拟存储器:抽象概念,它为每个进程提供一个假象,好像每个进程都在独占地使用主存。

每个进程看到的存储器都是一致的,称之为虚拟地址空间

八、简单地看看每一个区,从最低的地址开始,逐步向上研究

1、程序代码和数据区:代码是从同一固定地址开始,紧接着的是和C全局变量想对应的数据区。

2、堆:运行时堆。代码和数据区在进程一旦开始运行时就被指定了大小的,于此不同,堆可以运行时动态的扩展和收缩

3、共享库:在地址空间中间附近是一块用来存放像C标准库和数学库这样共享库的代码和数据的区域

4、栈:位于虚拟地址空间顶部的是用户栈,编译器用它来实现函数调用。和堆一样,用户栈在程序执行期间可以动态的扩展和收缩,每次我们调用一个函数时,栈就会增长,每次我们从函数返回时,栈就会收缩。

5、内核虚拟存储器:内核是操作系统总是驻留在存储器中的部分,地址空间顶部的四分之一部分是为内核预留的。应用程序不允许读写这个区域的内容或者直接调用内核代码定义的函数。

虚拟存储器的用作需要硬件和操作系统软件间的精密复杂的相互合作,包括对处理器生成的每个地址的硬件翻译,基本思想是把一个进程虚拟存储器的内容存储到磁盘上,然后用主存作为磁盘的高速缓存。

6、文件:只不过是字节序列,每个I/O设备,包括磁盘、键盘、显示器,甚至于网络,都可以被看成是文件。系统中所有的输入输出都是通过使用称为UnixI/O的以小组函数调用读写文件来实现的。

我们一直把系统视为一个独立的硬件和软件的集合体,实际上,现代系统经常是通过网络和其他系统连接到一起的。从一个单独的系统来看,网络又被视为又一个I/O设备。当系统从主存拷贝一串字符到网络适配器时,数据流经过网络到达另一台机器,而不是到达本地磁盘驱动器。相似地,系统可以读取从其他机器发送来的数据

,并把数据拷贝到自己的主存。

我们可以使用熟悉的telnet应用在一个远程主机上运行hello程序,需要五步:

1、用户在键盘上输入“hello”

2、客户端向telnet服务器发送字符串“hello”

3、服务器向shell发送字符串“hello”,shell运行hello程序并将输出发送给telnet服务器

4、telnet服务器向客户端发送字符串“hello  world\n”

5、客户端在显示器上打印“hello world\n”





一旦我们了解了编译器和机器级代码我们就能通过编写可以更高效编译的源代码,来分析如何最大化程序的性能

三种最重要的数字编码

1、无符号编码:基于传统的二进制表达法的,表示大于或等于0的数字。

2、二进制补码编码:表示有符号整数的最常见的方式,有符号整数就是为正或者为负的数字。

3、浮点数编码:表示实数的科学记数法的以二为基数的版本。

计算机的表示法用有限的位数来对一个数字编码,因此当结果太大以至于不能表示时,某些运算就会溢出(overflow).结果会违背整数运算属性。

由于表示的精度有限,浮点运算时不可以结合的。

例如:


          计算机用几种不同的进制表示来编码数值。通过直接操作位级的数字表示,我们得到了几种进行算术运算的方式。理解这些技术对于理解编译算数表达式时产生的机器级代码是很重要的。

           C++编程语言建立在C之上,使用完全相同的数字表示和运算。JAVA语言创造了一套新的数字表示和运算标准。C标准被设计为允许多种实现方式,而JAVA标准在数据的格式和编码上是详细而精确的。

大多数计算机用字节作为最小的可寻址的存储器单位,而不是访问存储器中单独的位。机器级程序将存储器视为一个非常大的字节数组,称为虚拟存储器。每个字节都有一个唯一的数字来标识,称为它的地址,所有地址的集合就称为虚拟地址空间。

编译器和运行时系统的一个任务就是 将这个存储器空间划分为更可管理的单元,来存放不同的程序对象(程序数据、指令和控制信息),有各种机制可以用来分配和管理程序不同部分的存储,这种管理完全是在虚拟地址空间内完成的。

C编译器还把每个指针和类型信息联系起来,这样它就可以根据指针值的类型,生成不同的机器级代码来访问存储在指针所指向位置处的值。

C中指针的角色:指针式C的一个重要特性它提供了引用数据结构的元素(包括数组)的机制,就像一个变量。

指针有两个方面:它的值和它的类型。

它的值表示的是某个对象的位置,而它的类型表示那个位置上所存储对象的类型(如:整数或者浮点数)

二进制,而十进制,二进制表示法太冗长,而十进制表示法,与位模式的相互转化很麻烦。替代的方法:我们以16为基数或者叫做十六进制数来书写位模式。十六进制(Hex)使用使用数字“0”~“9”以及字符“A”~“F”来表示16个可能的值。



OX173A4C       


  当x的值为2的幂时,也就是,对于某个n,x=2^n,我们可以轻松地将x写成十六进制形式,只要记住x的二进制表示就是1后面跟n个0.

十进制和十六进制表示之间的转换需要使用乘法或者除法来处理,将一个十进制数字x转换为十六进制的,我们可以反覆地用16除x,得到一个商q和一个余数r,也就是x=q.16+r。然后我们用十六进制数字表示的r作为最低位数字,并且通过对q反复进行这个运算过程得到剩下的数字。例如:

314156=19634*16+12     (C)

19634=1227*16+2           (2)

1227=76*16+11            (B)

76=4*16=12              (c)

4=0*16+4        (4)

所以十六进制数位0x4CB2C      

反过来,将十六进制数转化为十进制数字,我们可以用相应的16的幂乘以每个十六进制数字,比如:0x7AF

我们计算他对应的十进制值为7*16^2+10*16+15=7*256+10*16+15=1792+160+15=1967

十六进制(hex)十进制(decimal)

#Convert  list  of  decimal  numbers   into   hex  十进制转化为十六进制


























       







  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值