第二章内容为p58~p124
概要
- 无符号整数(unsigned)基于传统的二进制编码, 补码(two's-complement)是表示有符号整数最常见的方式, 浮点数(floating-point)是表示实数的科学计数法基数为2的版本
- 以有限位的方式表示数字, 在计算时时常会超出表示范围(即溢出overflow), 这经常会导致系统安全漏洞, 遭受黑客攻击
- 整数的表示范围较小, 是精确的; 浮点数的表示范围较大, 但是是近似的
- C语言的演变: GNU C > ANSI C > ISO C90(C89) > ISO C99 > ISO C11(2011)
信息存储
- 程序将内存视为一个大的字节数组, 称为虚拟内存(virtual memory), 每个字节都有一个地址, 所有可能地址的集合称为虚拟地址空间(virtual address space)
- 我们将程序称为"32位程序"或"64位程序"时, 区别在于该程序是如何编译的, 而不是运行时的机器类型
- 同样的类型在不同的机器和编译器下的大小是不一致的, 这导致移植问题. 程序开发时应尽量使用大小确定的数据类型, 或使用
sizeof
进行动态获取
大端法和小端法
一个对象, 如int类型, 可能占据多个字节的空间, 一般分配连续的地址空间进行存储. 对于这个对象, 有的机器选择从小到大存储, 有的从大到小存储, 分别为小端法和大端法. 如int类型的值0x01234567, 大端法(01-23-45-67), 小端法(67-45-23-01). Android和IOS是小端模式, 大多数Inter兼容机是小端模式. 这也会导致移植问题
表示字符串
C语言中字符串被编码位以一个null结尾的字符数组, 每个字符以一个标准编码(如ASCII)表示, 在任何系统上都得到同样的结果, 与字节顺序和字大小规则无关. 因而文本数据比二进制有更强的平台独立性. 所以为了二进制传输安全, base64编码会将二进制编码为64个常见且可打印的字符, 再进行传输, 虽然会增加传输的大小, 但传输的可靠性得到了保证, 常见于email传输中. 参考链接
整数表示
无符号整数编码B2Uw(Binary to Unsigned)
w位的无符号整数编码范围为\([0, 2^{w} - 1]\)
\(B2U_{w}(\overrightarrow{x}) = \sum\limits_{i=0}^{w-1}x_{i}2^{i}\)
有符号整数编码B2Tw(Binary to Two's-complement)
w位的有符号整数编码范围为\([- 2^{w-1}, 2^{w-1} - 1]\)
\(B2T_{w}(\overrightarrow{x}) = -x_{w-1}2^{w-1} + \sum\limits_{i=0}^{w-2}x_{i}2^{i}\)
无符号数和有符号数的转换
C语言中的有符号数和无符号数
当执行一个运算时, 如果一个运算数是有符号数一个是无符号数, 那么C语言会隐式地将有符号数强制类型转换为无符号数, 并假设这2个数都是非负的来执行这个运算.
扩展一个数字的位表示
- 无符号数的扩展, 直接高位补0
- 补码数的扩展, 高位补最高位, 1011 = 1 1011 = 11 1011 = 111 1011 = -5
截断数字
关于有符号数和无符号数的建议
C语言中unsigned int的减法要特别注意, 一旦结果为负值, 预期是负值, 然后实际是很大的正整数, 很多逻辑就会出现问题.
另外一种情况是参数的不匹配, 如函数参数是int, 函数内部调用另外一个函数传的int, 而形参是unsigned int(如size_t), 传的值是负值就容易出问题.
练习题2.12
这个练习题比较有意思, 如下:
A. 利用了&的特性, 1保留0清空, 所以答案为x & 0xFF, 8位以上的高位都可能为0, 都满足条件
B. 很难, 想了半天, 看了答案才明白. 利用了^的特性, 1取反0保留, 所以高位取反, 如果用0xFFFF00, 则不能满足不同位数的清空, 所以要用一个反, 答案为 x ^ ~0xFF
C. 利用了|的特性, 1设置为1, 0保留, 低位设置为1, 所以答案为x | 0xFF