信息的表示和处理
P20
无符号数:编码基于传统的二进制表示法(大于或者等于零的数字)。
补码:编码是表示有符号整数的最常见方式(为正或者为负的数字)。
浮点数:编码是表示实数的科学记数法的以二为基数的版本。
整数的表示虽然只能编码一个相对较小的数值范围,但是是精确的;而浮点数虽然可以编码一个较大的数值范围,但是这种表示是近似的表示。
大量的计算机安全漏洞都是由于计算机运算的微妙细节引发的。
P22
计算机使用大多数使用8位的块,或者字节,作为最小的可寻址的储存单位,而不是在存储器中访问单独的位。
十六进制表示法:
拿二进制作中间结果。
字:
每台计算机都有字长,指明整数和指针的标称大小。
字节决定的最重要的系统参数就是虚拟地址空间的最大大小。
对于一个字长为w的机器而言,虚拟地址范围0~2*(w-1),程序最多访问2*w个字节(常见w=32或者64)
数据大小:
计算机和编译器支持多种不同编码的数字格式,比如整数和浮点数,以及其他长度的数字。比如,许多机器都有处理单个字节的指令,也有处理表示为2字节或者4字节或者8字节的整数指令,还有些指令支持表示为4字节和8字节的浮点数。
gcc-m32可以在64位机上生成32位的代码。
P26
寻址和字节顺序:
对于跨越字节的程序对象,我们必须建立两个规则:这个对象的地址是什么,以及在存储器中如何安排这字节。
字节的顺序是网络编程的基础,小端是:“高对高,低对低”,大端与之相反。
P28
P32
逻辑运算(结果是0或者1):
与:&&
或:||
非:!
1表示TURE 0表示FALSE
位运算(结果是位向量):
与: &
或: |
非: ~
异或:^
按位进行运算
P33
掩码是位运算的重要应用,位特定位可以置零或者置一(用来选择性屏蔽信号)
P38
整型数据类型:
表示有限范围的整数。
每种类型都能用关键字来指定大小,包括char或者short或者long或者 long long ,同时还可以指定是非负数(unsigned)或者可能是负数(默认)。
这些不同大小的分配的字数会根据机器的字长和编译器有所不同。
要用C99中的“long long”类型。编译是要用gcc-std=C99
P39
无符号数的编码:
对于每一个长度为w的位向量,都有一个唯一的值与之对应;反过来,在0~2*w-1之间的每一个整数都有唯一的长度为w的位向量二进制与之对应。
补码编码:
对于每一个长度为w的位向量,都有一个唯一的值与之对应;反过来,每个介于在-2*(w-1)和2*(w-1)-1之间的每整数都有唯一的长度为w的位向量二进制与之对应。
P44
有符号跟无符号的转换:
有符号和无符号的规则,位向量不变
位+上下文
P48
计算机的负数是对应正数的取反+1
P49
0扩展:
将一个无符号数转换为一个更大的数据类型,我们只需要简单地在表示的开头添加0
符号扩展:
将一个补码数字转换为一个更大的数据类型,规则是在表示中添加最高位的有效位的副本
P52
就像我们看到的,有符号数到无符号数的隐式强制类型转换导致了某些非直观的行为。而这些非直观的特性经常导致程序错误,并且这种包含隐式强制类型转换细微的差别错误很难被我们发现,因为这种强制类型的转换是代码中没有明确指示的情况下发生的。
如练习题2.25
length作为一个无符号数来传递很自然,i<=length-1也很自然,但是组合到一起,代码将试图访问数组a的非法元素。
P54
溢出:
在无符号算术运算中,没有所谓的“溢出”一说:所有的无符号运算都是以2的n次方为模,这里的n是结果中的位数。如果算术运算符的一个操作数为有符号整数,另一个为无符号整数,那么有符号整数会被转换成无符号整数,“溢出”也不可能发生。但是,当两个操作数都是有符号数时,溢出就有可能发生,而且溢出的结果是未定义的。当一个运算的结果发生溢出时,做出任何假设都是不安全的。
避免:
一个正确的方法是依赖于无符号算术的良好定义,即要在有符号和无符号之间进行转换:
P67
关于整数运算的最后的思考:
计算机执行的整数的运算其实是一种模运算的形式
无论运算数是以无符号形式还是以补码的形式的表示的,都有完全一样或者非常类似的位级行为
浮点数:
浮点表示对如V=xX2*y的有理数进行编码
它对执行涉及非常大的数字(|V|>>0)非常接近于0(|V|<<1)的数字,以及更普遍地作为实数运算的近似值的计算,都是很有用的
浮点数有科学的计算基础就很好理解,IEEE标准
P68
IEEE :
Institute of Electrical and Electronics Engineers (IEEE) 美国电气和电子工程师协会
IEEE被国际标准化组织授权为可以制定标准的组织,设有专门的标准工作委员会,有30000义务工作者参与标准的研究和制定工作,每年制定和修订800多个技术标准。
IEEE的标准制定内容有:电气与电子设备、试验方法、原器件、符号、定义以及测试方法等。
浮点数运算的不确定性与舍入:
1.向偶舍入
2.向零舍入
3.向下舍入
4.向上舍入
P70
IEEE浮点标准用V=(-1)*s XMX 2*E 来表示一个数:
符号:s决定这个数是负数(s=0)还是正数(s=1)。而对于0的符号位特殊情况处理。
尾数:M是一个二进制小数,范围为1~2-ε或者0~1-ε(ε=1/2的n次幂)
阶码:E对浮点数加权,权重是2的E次幂(可能为负数)
编码规则:
float:
s字段为1位,exp字段为k=8位,frac字段为n=23位,得到一个32位的表示。
double:
s字段为1位,exp字段为k=11位,frac字段为n=52位,得到一个64位的表示。
P74
明白整数与浮点数的转换规则
IEEE 754对有效数字M和指数E还有一些特别规定:
(1)E不全为0或不全为1:
这时浮点数就采用上面的规则表示即指数E的计算值减去127(或1023)得到真实值再将有效数字M前加上第一位的1。
(2)E全为0:
这时浮点数的指数E等于1-127(或者1-1023)有效数字M不再加上第一位的1而是还原为0.xxxxxx的小数。这样做是为了表示±0
以及接近于0的很小的数字。
(3)E全为1:
这时如果有效数字M全为0表示±无穷大(正负取决于符号位s)如果有效数字M不全为0表示这个数不是一个数(NaN)。
小结:
在相同长度的无符号和有符号的整数之间进行强制类型的转换时,大多数的C语言实现遵守的原则是底层的位模式不变。在补码的机器上,对于一个w位的值,这种行为是由函数T2Uw和函数U2Tw来描述的。C语言隐式的强制类型的转换会出现许多程序员无法预计的结果,常常导致程序出出现错误。
由于编码长度有限,与传统整数和实数的运算相比,计算机运算具有完全不同的属性。当超过表示的范围时,有限长度能够引起数值的溢出。
我们必须非常小心的使用浮点运算,因为浮点运算只有有限的范围和精度,而且不遵守普通的算术属性,比如结合性。