2.1.3 寻址和字节顺序
假设类型为int的变量x的地址为0x100,那么,x的4字节(假设int为4字节)将被储存在0x100、0x101、0x102、0x103位置。
1、大小端法
☆一个w位的整数,其位表示[xw-1,…,x0],其中xw-1是最高有效位,x0是最低有效位。将w假设为8的整数,这些位就可以视作字节(1byte=8bit),同样可以分为最高有效字节和最低有效字节,这些字节由8位组成。如果机器选择在内存中按照从最低有效字节到最高有效字节的顺序储存对象则为小端法。
☆int类型的x变量的值用十六进制表示为0x01234567。大小端法如图:
值0x01234567,高位字节的十六进制值为0x01(4位表示一个十六进制数字)。目前许多微处理器是双端法,而操作系统可能起到决定性作用:Android和iOS只能运行小端模式。
2、字节顺序所带来的问题
☆通过网络传送二进制数据。小端法机器产生的数据被发送到大段机器时,接收程序会发现,字里的字节成了反序的。所以网络应用程序的编写需要遵守约定的字节顺序规则。
☆阅读表示整数数据的字节序列时。通常发生在检查机器程序时。使用反汇编器工具阅读小端法机器生成的机器级程序表示时,经常会将字节按照相反的顺序显示。
☆编写规避正常类型的程序时(举例中使用c语言通过强制类型转换或联合允许一种数据类型引用另一个对象,而这种数据类型和创建这个对象时定义的数据类型不同。用不同机器运行程序打印出来的值字节序列不尽相同,这是机器采用的大小端法不统一,而指针值(被强制转型为数据类型)却是完全不同!!!这是由于不同机器或操作系统配置使用不同的储存分配机制)。
2.1.4 表示字符串
字符串“12345”以十六进制、以ASCII码表示为31 32 33 34 35 00。00是终止符代码。在使用ASCII码作为字符码的任何系统上都将得到相同的结果,与字节顺序和字大小规则无关。因而,文本数据比二进制数据具有更强的平台独立性。
2.1.5 表示代码
不同的机器类型使用不同的且不兼容的指令和编码方式。即使是完全一样的进程,运行在不同的操作系统上也会有不同的编码规则,因此二进制代码是不兼容的。二进制代码很少能在不同机器和操作系统组合之间移植。
2.1.6 布尔代数简介
布尔通过逻辑值true和false编码为二进制1和0,设计出一种代数,以研究逻辑推理的基本原则。
☆最简单的布尔代数式在二元集合{0,1}的基础上定义的。布尔代数中简单的几种运算如下图:NOT:p=0,~P=1;AND:p=1(true)且q=1时,p&q=1;OR:只要其中之一为真,则p|q=1为真;EXCLUSIVE-OR:当两者仅有一者为真则为p^q=1真。
☆布尔运算扩展为位向量运算。 位向量就是固定长度为w、由0和1组成的串。举例:w=4,参数a=[0110],b=[1100]。那么4种运算a&b、a|b、a^b、~b分别得到以下结果:
☆表示有效集合。我们可以通过位向量[aw-1,…,a0]编码任何子集A<={0,1,…,w-1},其中ai=1当且仅当i属于A。位向量a=[01101001]表示集合A={0,3,5,8},而b=[01010101]表示集合B={0,2,4,6}。这种编码集合的方法,布尔运算|和&分别对应集合的并和交,而~对应于集合的补。a&b=[01000001],而A交B={0,6}。
☆练习题:
2.1.7 C语言中的位级运算
☆C语言中的位级运算,下图是对char数据类型表达式求值的例子:
习题:
☆掩码运算。掩码0xFF(最低的8位为1)表示一个字的低位字节。位级运算x&0xFF将生成一个由x的最低有效字节组成的值,而其他的字节就被重置为0。若x=0x89ABCDEF,则x&0xFF=0x000000EF。表达式~0将产生一个全为1的掩码,不管机器的字长多少。
习题:
2.1.8 C语言中的逻辑运算
☆C语言中的逻辑运算。逻辑运算认为所有非零参数都表示true,而0表示false。分别返回1和0。举例如下:
逻辑运算符&&和||与它们对应的位级运算&和|之间的第二个重要区别:如果对第一个参数就能确定表达式的结果,那么逻辑运算符就不会对第二个参数求值。
习题:
2.1.9 C语言中的移位运算
☆左移:对于一个位表示为[xw-1,…,x0]的操作数x,C表达式x<<k会生成一个值,其位表示为[xw-k-1,…,x0]。也就是说,x向左移动k为,丢弃最高的k位,并在右端补上k个0。移位量应该在0至w-1之间的值,移位运算时可以从左向右可结合的,所以x<<j<<k等价于(x<<j)<<k。
☆右移:逻辑右移在左端补k个0。得到的结果是[0,…,0,xw-1,…,xk]。算术右移是在左端补齐k个最高有效位的值,得到的结果是[xw-1,…,xw-1,…,xk]。
☆举例:(斜体表示填充值)
☆注意:C语言并没有定义有符号数应该使用算术右移或者是逻辑右移。实际上,几乎所有的编译器/机器组合都对有符号数使用算术右移,而且程序员也都假设机器会使用这种右移。另一方面,对于无符号数,右移是逻辑的。与C相比,java明确定义,x>>k会静x算术右移k个位置,而x>>>会对x做逻辑右移。
☆练习题(习题答案在章末):