学习本章的意义可以用这么一句话概括:
to write programs that work correctly over the full range of numeric values and that are portable across different combinations of machine, operating system, and compiler.
2.1 Information Storage
计算机使用1个byte或者8个bit作为最小的可寻址内存单元。一个machine-level的程序将内存看作一个非常大的字节数组,叫做虚拟内存。内存中的每一个字节都由一个唯一的数字来表示,这个数字就是地址,所有地址的集合就是虚拟地址空间。既然是虚拟的,这个空间实际上只是一个概念。实际是利用DRAM、闪存等硬件和 *** 作系统软件一起实现的。
在后续的章节中,我们将会学习编译器和run-time系统如何把内存空间划分为更易于管理的单元,以存储不同的程序对象(程序数据、指令和控制信息)。各种机制被用于分配和管理程序不同部分的存储。这些管理都是在虚拟地址空间中执行的。例如,C语言中指针的值就是某个存储块的第一个字节的虚拟地址,不管这个指针是是想int、strcut还是别的什么。C语言的编译器把类型信息与每个指针关联起来,这样就可以生成不同的机器级代码来访问存储在指针指定位置的值,该位置取决于该值的类型。尽管C编译器维护这种类型信息,但实际的machine-level程序没有关于数据类型的信息,只是将每个程序对象视作一个字节块,将程序本身视作一个字节序列。
2.1.1 Hexadecimal Notation(16进制计数法)
8bit可以表示的二进制范围是00000000~11111111,如果看作是十进制整数,那就是0~255。这两种表示法都不太行,二进制太长,十进制与bit之间转换很繁琐。所以现在使用16进制(hex)。在16进制的描述下,一个byte的范围是00~FF。
在C里,以0x开头的数字通常用16进制去理解。2进制-10进制-16进制之间的对应表如下,对各位搞计算机的来说应该是小菜一碟
书里介绍了一种2进制速转16进制的方法,仅适用于2的整数次幂。假设是n次幂,那么把n拆分成i+4j的形式,其中0≤i≤3。如果是2^11,那么11=3+4*2,i=3,相应的16进制第一个数就是8,后面j=2,说明8后面跟两个0,得到16进制数0x800。可以看到i和16进制第一个数之间是由对应关系的,具体的,i=0对应1,i=1对应2,i=2对应4,i=3对应8。
书里介绍了一种10进制转16进制的方法,就是疯狂除16,得到商再除16,最后把整个过程得到的余数倒叙排列就得到结果。
书里介绍了一种16进制转10进制的方法,就是16进制的各位数乘相应的16的幂次再累加。
2.1.2 Data Size
每个计算机都有一个word size,指明指针数据的标称大小。由于虚拟地址是用这个word编码的,所以word的大小决定了虚拟地址空间的大小。举个例子,word是wbit的,那么虚拟地址的范围就是0~2^w-1,程序最多访问2^w个字节。
这就是为什么从32bit的word size扩展到64bit的word size,这样是把虚拟地址空间从4x10^9扩展到1.84x10^19byte。
在linux上用32bit编译的命令:gcc -m32 prog.c;用64bit编译的命令:gcc -m64 prog.c
这样分别编译得到32位的程序和64位的程序。
以C程序为例,C会提供多种大小的数据
程序员应该使自己写的程序能够在不同的机器和编译器之间移植。可移植性的一个方面是使程序对不同数据类型的确切大小不敏感。C语言对不同数据类型设置了数字范围的下界,但没有给出上界。在32->64的过渡过程里,会出现一些问题。举个例子,很多人都会证明一个int去存储指针,对于32位程序,这没问题,但64位程序就会出现一些问题。
2.1.3 Addressing and Byte Ordering(寻址和字节排序)
对于跨越多个字节的程序对象,必须建立两个约定,即确定对象的地址是什么,以及如何在内存中排列字节。在几乎所有机器中,多字节对象被存储为一个连续的字节序列,对象的地址由所使用的字节的最小地址给出。举个例子,假设有个int类型,大小4byte,地址是0x100,那么这个东西占据的内存是0x100、0x101、0x102、0x103。
对于表示对象的字节排序,有两个常见约定。考虑一个具有位表示形式的w-bit的整数[Xw-1,Xw-2,..., X1, X0],Xw-1是最重要的bit,X0是最不重要的。假设w是8的倍数,那么这些bit可以分组成byte,最重要的byte有8个bit,分别是[Xw-1, Xw-2, ..., Xw-8],最不重要的是[X7, X6, ..., X0]。一些机器选择将对象按从低到高字节的顺序存储在内存内,另一些机器按从高到低字节的顺序存储在内存内。(说白了就是地址的小端和大端)假设把0x12345678这个数放在内存里,大端和小端的存放示意图如下:
大多Intel的机器是小端模式,许多微处理芯片是双端的,表示这种芯片既可以小端也可以大端。不难考虑到可能会出现一种情况是小端模式的A给大端模式的B发送了一串信息,那么B在接受处理这个信息的时候就有问题。所以需要遵循一个约定,确定使用哪种顺序。
2.1.4 Representing String
在C语言里,字符串由以null字符结束的字符数组编码。每个字符都由一些标准编码表示,最常见的是ASCII字符编码。
2.1.5 Represeting Code
考虑下面的代码
当在机器上编译时,生成具有以下字节表示的机器码:
可以发现码字是不同的,不同的机器使用不同且不兼容的指令和编码。即使是运行不同 *** 作系统的相同处理器也有不同的编码约定,因此是不兼容二进制的。二进制代码很少能在不同的机器和 *** 作系统组合之间移植。
计算机系统的一个基本概念是,从机器的角度看,程序只是一个字节序列。机器没有关于原始源程序的信息,可能除了一些辅助表来帮助调试。
2.1内容忒多了也。。。。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)