由于本站对数学公式暂不支持,所以本章中公式均采用图片的方式进行插入。

第二章 信息的表示和处理


二值信号 能够很容易地被表示、存储和传输。

通过使用标准的字符码,能够对文档中的字母和符号进行编码。

  • 无符号(unsigned) 编码基于传统的二进制表示法,表示大于或等于零的数字。
  • 补码(two's-complement) 编码是表示有符号整数最常见的方式。
  • 浮点数(floating-point) 编码是表示实数的科学计数法的以2为基数的版本。

计算机表示法是用 有限数量的位 来对一个数字编码,因此某些运算可能会溢出。

整数的表示虽然只能编码一个相对较小的数值范围,但这种表示是精确的;而浮点数虽然可以编码一个较大的数值范围,但这种表示只是近似的。由于 表示精度有限,浮点运算是不可结合的

信息存储


大多数计算机使用8位的块,即 字节(byte) ,作为最小的可寻址内存单位,而不是访问内存中单独的位。
内存的每个字节都由一个唯一的数字来标识,称为它的地址,所有可能地址的集合就称为虚拟地址空间。

C语言中的指针有两个属性:值和类型,它的值表示某个对象的位置,类型表示那个位置上所存储对象的类型。

十六进制表示法


二进制表示有些冗长,常用十六进制(hexadecimal)代替,一个字节的值域为[0x00, 0xFF]。
C语言中,以0x0X开头的数字常量被认为是十六进制的值。十六进制中,如果二进制表示下位总数不是4的倍数,那么前面可以用0补足。

字数据大小


每台计算机都有一个字长,指明指针数据的标称大小,虚拟地址是以这样一个字来编码的。
对于一个字长为w位的机器而言,虚拟地址的范围是[0,2 w - 1]。32位字长机器限制虚拟地址空间为4GB,而扩展到64位字长使得虚拟地址空间为16EB。大多数64位机器可以运行32位机器编译的程序,这是一种 向后兼容
我们将程序称为“32位程序”或“64位程序”时,区别在于该程序是如何编译的。

ISO C99引入了int32_tint64_t,它们分别为4字节和8字节,其数据大小是固定的,不随编译器和机器设置而变化 ,使用确定大小的整数类型是程序员准确控制数据表示的最佳途径。

指针使用程序的全字长。

程序员应该力图使程序在不同的机器和编译器上 可移植 ,可移植性的一个方面就是使程序对不同数据类型的确切大小不敏感。

寻址和字节顺序


对于跨越多字节的程序对象,必须建立两个规则: 这个对象的地址是什么 ,以及 在内存中如何排列这些字节
几乎所有机器上,多字节对象都被存储为连续的字节序列,对象的地址为 所使用字节中最小的地址
- 小端法(little endian) :最低有效字节在最前面(最前面指内存位置较小处)
- 大端法(big endian) :最高有效字节在最前面

例:假设x类型为int,位于地址0x100处,十六进制为0x01234567,不同机器类型字节排列方式分别为
- 小端法:67(0x100) 45(0x101) 23(0x102) 01(0x103)
- 大端法:01(0x100) 23(0x101) 45(0x102) 67(0x103)

现在有些比较新的微处理器是双端法,可以把它们配置成作为大端或者小端的机器运行。Android和iOS只能运行于小端模式。
选择何种字节顺序没有技术上的理由,只要选择了一种规则并且始终如一地坚持,对于哪种字节排序的顺序都是任意的。
无论为哪种类型机器所编译的程序都会得到同样的结果,不过在不同类型的机器之间通过网络传送二进制数据时,一个常见的问题是当小端法机器产生的数据被发送到大端法机器或者反过来时,接收程序会发现字里的字节成了反序的,为了避免这类问题, 网络应用程序的代码编写必须遵守已建立的关于字节顺序的规则

表示字符串


C语言中字符串被编码为一个以null(值为0)字符结尾的字符数组。

在使用ASCII码作为字符码的任何系统上都将得到相同的结果,与字节顺序和字大小规则无关。Linux中执行命令man ascii可以得到一张ASCII字符码的表。
UTF-8表示将每个字符编码为一个字节序列,这样标准ASCII字符还是使用和它们在ASCII中一样的单字节编码。

不同机器类型使用不同的且不兼容的指令和编码方式,二进制代码常常是不兼容的。
从机器角度来看, 程序仅仅是字节序列

布尔代数简介


布尔代数 将逻辑值TRUE(真)和FALSE(假)编码为二进制值1和0。

  • 当P等于0时,~P等于1。
  • 只有当p=1且q=1时,p&q才等于1。
  • 当p=1或q=1时,p|q才等于1。
  • 当p=1且q=0,或者p=0且q=1时,p^q等于1。

C语言中的位级运算


位向量的运算可以定义为参数的每个对应元素之间的运算,假设a和b分别表示位向量[aw-1, aw-2,...,a0] 和[bw-1, bw-2,...,b0],将a&b定义为一个长度为w的位向量,其中第i个元素等于ai & bi,0<= i < w。

  • 布尔运算&|满足分配律:a&(b|c) = (a&b) | (a&c),a|(b&c) = (a|b) & (a|c)
  • 对于任何值a来说,a^a = 0
  • 重新排列组合顺序,异或的属性也仍然成立,因此有(a ^ b) ^ a = b

位级运算的一个常见用法就是实现 掩码运算 ,比如位级运算x & 0xFF生成一个由x的最低有效字节组成的值,而其他的字节就被置为0。

C语言中的逻辑运算认为非零参数都表示TRUE,而参数0表示FALSE。

C语言中的逻辑运算符&&||,如果对第一个参数求值就能确定表达式的结果,那么逻辑运算符就不会对第二个参数求值。

x向左移动k位,会丢弃最高的k位,并在右端补k个0。(应该保持位移量小于待移位值的位数)

  • 逻辑右移:右移k位则丢弃最低的k位,并在左端补k个0
  • 算术右移:右移k位则丢弃最低的k位,并在左端补k个最高有效位的值

整数表示


C语言中的整数数据类型取值范围是不对称的——负数的范围比整数的范围大1(如short的范围是[-32768,32767])。
C和C++支持有符号数(默认)和无符号数,Java只支持有符号数。

整数运算


浮点数


C语言提供了两种不同的浮点数据类型:float和double,分别对应于单精度和双精度浮点。
这类及其使用向偶数舍入的舍入方式。

  • 从int转换成float,数字不会溢出,但是可能被舍入
  • 从int或float转换成double,因为double有更大的范围,也有更高的精度,所以能够保留精确的数值
  • 从double转换成float,因为范围要小一些,精度也较低,所以值可能溢出或被舍入
  • 从float或double转换成int,值会向零舍入,进一步说值可能会溢出。一个从浮点数到整数的转换,如果不能为该浮点数找到一个合理的整数近似值,就会产生一个整数不确定值(与Intel兼容的微处理器指定位模式为[10..00])。因此表达式(int)+1e10会得到-21483648

评论

还没有登陆?评论请先登陆注册

还没有评论,抢个沙发吧!

 联系方式 contact me

Github
Email
QQ
Weibo