- 信息存储
- 十六进制
- 十六进制的表示
- 十六进制与二进制、十进制的转化
- 字数据大小
- 寻址和字节顺序
- 表示字符串
- 表示代码
- 布尔代数
- C语言中相关运算
- 位级运算:&,|,~
- 逻辑运算:&&,||,!
- 移位运算:<<,>>
- 十六进制
- 整数表示
- 整形数据表示
- 编码
- 无符号数(Unsigned)
- 补码(Two's-Complement)
- 无符号数和有符号数之间的转换
- C语言中无符号数与有符号数的转换
- 扩展位表示
- 截断数字
- 整数运算
- 加法
- 无符号加法
- 补码加法
- 取非
- 无符号数
- 补码
- 乘法
- 无符号数
- 补码
- 乘以常数
- 与2的幂相乘
- 与任意常数相乘
- 除以2的幂
- 无符号数
- 补码
- 加法
- 浮点数
- 二进制小数
- IEEE浮点表示
- 规格化
- 非规格化
- 特殊值
- 无穷大
- NaN(Not-a-Number)
- 舍入规则
- 浮点运算
- 加法
- 乘法
- 类型转换
信息存储
大多数计算机以字节(1 byte = 8 bits)作为最小可寻址的内存单位。
虚拟内存:机器级程序将内存视为字节数组。
地址:标识每个字节的唯一数字。
虚拟地址空间[1]:所有可能的地址集合。
十六进制
十六进制的表示
-
前缀0x/0X,字母可用大写A - F或小写a - f
记住A,C,F的十进制值
十六进制与二进制、十进制的转化
十六进制&二进制:四位二进制转化为一位十六进制,位数缺少时整数部分左侧补零,小数部分右侧补零。
-
十六进制&十进制:乘除法
2的非负整数n次幂转化为十六进制:n = i + 4 * j (i = 1, 2, 3)时,十六进制表示为2的 i 次方后有 j 个0
字数据大小
字长决定了虚拟地址空间的最大大小:字长w位,虚拟地址范围为0 ~ 2^w - 1,即可以访问2^w个字节。
程序时32位还是64位取决于它是如何编译的。
寻址和字节顺序
多字节对象被存储为连续的字节序列。
-
字节存储顺序:一个数据类型内部字节的存储顺序
大端法:高位字节优先存储
-
小端法:低位字节优先存储
大端法(big endian)和小端法(little endian)取自《格列佛游记》中打破鸡蛋的方式。原文暗讽英法两国持续的战争,而这里则暗示选择两种存储顺序没有技术上的理由,无谓好坏。
-
需要注意字节存储顺序的三种情况
不同机器通过网络传送二进制数时,由小端法机器传送给大端法机器的字节顺序会被认为是反序,反之亦然。此时应统一编写网络应用程序的字节顺序规则,由发送方机器将其内部表示先转化为网络标准,再由接收方机器将收到的网络标准转化为其内部表示。
阅读小端法机器的程序表示时。
-
规避正常类型系统时,即运用了强制类型转换或联合。例如:运用强制类型转换生成对象的字节表示。
#include
typedef unsigned char *byte_pointer; //指向字节序列的指针 void show_bytes(byte_pointer start, size_t len){ size_t i; //size_t是表示数据结构大小的首选数据类型(这里为sizeof的结果) for(i = 0; i < len; i++) printf("%.2x", start[i]); //%.2x表示两位16进制数 printf("\n"); } void show_int(int x){ show_bytes((byte_pointer) &x, sizeof(int)); } void show_float(float x){ show_bytes((byte_pointer) &x, sizeof(float)); } void show_pointer(void *x){ show_bytes((byte_pointer) &x, sizeof(void *)); } //这里的强制类型转换并未改变指针, 只是告诉编译器以新的数据类型看待被指向的数据 //例如, show_int中将&x看作int指针时, 进入"下一个"地址会跨越四个字节; 看作char指针时, 进入"下一个"地址只会跨越1个字节
表示字符串
- 字符串编码以null(0x00)结尾。
- 最常见的字符编码是ASCII码。字符串的字节序列在使用ASCII编码的任何系统上都有相同结果,与字节顺序规则和字长大小无关。
表示代码
- 从机器的角度看,程序代码只是字节序列。
- 不同机器对于相同程序的二进制编码不同且不兼容。
布尔代数
- 位向量可用于表示有限集合的子集,位向量的与或非等价于集合的交并补。
- 布尔代数与整数算术有相似之处:交换律,结合律,分配律(布尔代数的分配律可以理解为对整数算术分配律的推广。因为布尔代数中,不仅&对|有分配律,|对&也有分配律)
C语言中相关运算
位级运算:&,|,~
-
掩码运算。掩码表示从一个字中选出的位的集合,如0xFF表示一个字低位字节都是1。x&0xFF表示x的最低字节不变,其他字节都被置为0。
习题2.10&2.11
注意:指向相同地址的两个指针,改变其中一个,则另一个也会变
#include
#include void inplace_swap(int *x, int *y){ *y = *x ^ *y; *x = *x ^ *y; *y = *x ^ *y; } void reverse_array(int a[], int cnt){ int first, last; for(first = 0, last = cnt - 1; first <= last; first++, last--) inplace_swap(&a[first], &a[last]); } int main(){ int a[5] = {1, 2, 3, 4, 5}; reverse_array(a, 5); for(int i = 0; i < 5; i++) printf("%d", a[i]); //最终结果为{5,4,0,2,1}, first = last时, *x = *y, *y = *x ^ *y = 0时, *x也被置为0 return 0; }
逻辑运算:&&,||,!
- 逻辑运算中,只有0(FALSE)和1(TRUE),所有非零参数均表示1(TRUE)
- 逻辑运算具有提前终止的特点。当第一个参数就能确定表达式的值时,就不会计算第二个参数。
移位运算:<<,>>
- 左移即在低位补0。右移分为逻辑右移和算术右移。逻辑右移在高位补0,算术右移在高位补符号位。
- 由w位组成的数据,移动k位。若k>w,则只视为移动k mod w位。移位指令只考虑移位量k的低logw位。
- 移位运算符合左结合律:x<
- 移位运算优先级低于加减法:x<
整数表示
整形数据表示
- unsigned / (signed) + char, short, int, long
- 数据类型取围:32位、64位、C语言标准均有不同
编码
无符号数(Unsigned)
- B2U
- UMax, UMin
- 无符号数编码具有唯一性(B2U是双射)
补码(Two's-Complement)
B2T
-
TMax, TMin
-TMax = 0 - TMax = TMax
补码编码具有唯一性(B2T是双射)
|TMin| = TMax + 1
UMax = 2 * TMax + 1
-1和UMax有相同的位模式
-
有符号数的其他表示方法
- 原码(Sign-Magnitude)
- 反码(Ones'-Complement):对于无符号数x,-x的w位表示在反码中相当于[11…1] - x,在补码中相当于2^w - x
无符号数和有符号数之间的转换
保持位模式不变
对于x,0≤x≤TMax时T2U(x) = U2T(x),否则转换时需对x加上或减去2^w
C语言中无符号数与有符号数的转换
- 显示转换:强制类型转换
- 隐式转换
- 不同类型变量赋值:保持被赋值的变量类型不变
- 输出函数printf中通过"%d"与"%u"进行转换
- 运算中,如果有符号数和无符号数同时出现,则视为无符号运算
扩展位表示
- 无符号数进行零扩展,值不变。
- 有符号数进行符号扩展,值不变。
- 高位全是1和只有最高位为1对数值大小没有影响,可用于简化运算。
截断数字
- 直接截断高位。
- 无符号数相当于取模(x%2^w = x')
- 有符号数相当于转化为无符号数取模后,再转化为有符号数。
有符号数和无符号数之间的转换容易引起错误。详见习题。
整数运算
模数运算形成数学结构:阿贝尔群
无符号数运算和补码运算有完全相同的位级表示。
加法
无符号加法
正常情况x+y的值保持不变,溢出情况的结果是x+y-2^w
检测无符号加法的溢出:对于无符号数s=x+y,当且仅当s 正常情况x+y的值不变,正溢出情况结果是,负溢出情况结果是。 检测补码加法的溢出:对于补码s=x+y,当且仅当x<0,y<0,s≥0时,发生负溢出;当且仅当x>0,y>0,s≤0时,发生正溢出。 得到取非结果的位级表示的方法:①按位取反后加一。②设k是最右边的1的位置,对k左边所有位取反即可。 对于无符号数-x,x=0时结果是其本身,否则结果是2^w-x 对于补码-x,x=TMin时结果是其本身,否则结果是-x x * y=(x * y) mod 2^w 将结果位级表示转化为补码即可 与2的k次幂相乘转化为左移k位实现。 将常数K表示为0和1交替的二进制序列,将乘法运算转化为移位运算和加减法的组合。 设K的二进制表示中所有的1连续出现,且从位置n到位置m有连续的1 形式1:x * K = (x< 形式2:x * K = (x<<(n+1)) - (x< 不符合条件的情况可通过变换得到。 除以2的k次幂转化为右移k位实现,得到向下取整的结果。 正数向下取整:除以2的k次幂转化为右移k位实现 负数向上取整:除以2的k次幂转化为,先加偏置量2^k-1=(1< “溢出”是针对码值转化为数值后,不符合直观运算规则而言的。但实际上码值运算规则无谓“溢出”,永远符合相同规则。如A+B=C就有C-B=A。 符号s:0正1负 尾数M:1 ~ 2-ε 或 0 ~ 1-ε 阶码E 符号位s编码符号s k位阶码字段exp编码E n位小数字段frac编码M E=Exp-Bias E=1-Bias exp=11...1,frac=00...0 exp=11...1,frac≠00...0 对于程序存储的管理完全是在虚拟地址空间中进行的。例如,指针指向的就是字节块的虚拟地址。 ↩补码加法
取非
无符号数
补码
乘法
无符号数
补码
乘以常数
与2的幂相乘
与任意常数相乘
除以2的幂
无符号数
补码
浮点数
二进制小数
IEEE浮点表示
规格化
非规格化
特殊值
无穷大
NaN(Not-a-Number)
舍入规则
浮点运算
加法
乘法
类型转换