信息存储
- 计算机使用字节,作为最小可寻找的内存单位,机器级程序将内存视为一个非常大的字节数组,称为虚拟内存,内存的每个字节都由一个唯一的数字来标识,称为地址。所有可能的地址集合,称为虚拟地址空间。
每台计算机都有一个字长,34位字长cpu的地址最大范围 0~2^34-1,64位字长cpu的地址范围0~2^64-1,大多数64位机器也可以运行32位机器编译的程序,这是一种向后兼容。
十六进制
计算机使用二进制存储信息,因为二进制表示比较麻烦,引入十六进制表示位模式。
- 十六进制:简写为hex,范围0-9 a-f 。 十六进制表示法,使用0x开头。比如0x01,0x02。
-
字节顺序
几乎所有的机器上,多字节对象被存储为连续的字节序列,对象的地址为使用字节中的最小地址。十六进制0x01234567
- 大端法:高位字节存入低地址,低位字节存入高地址。
- 小端法:低位字节存入低地址,高位字节存入高地址。
大端小端依赖于机器类型。如果在不同的机器上进行网络通信,就需要双端统一好字节顺序,避免数据错乱。
字符串
C语言中的字符串被编码为一个以null(值为0)为字符结尾的字符数组。
每个字符有编码标准。最常见的ASCII编码。对于中文。需要使用Unicode编码。
布尔代数
-
C语言中的位运算
‘|’ 代表或,‘&’代表与,‘~’代表取反,‘^’代表异或
位运算的一个常见用法就是实现掩码运算,比如x=0x89ABCDEF,如果要得到最低有效字节的值,可以使用运算x&0xFF得到。
C语言中的逻辑运算
逻辑运算认为所有的非零参数都表示为True,而参数零标识False。
C语言中的移位运算
- 左移:x向左移动k位,丢弃最高的k位,并在右端补k个0。
- 逻辑右移:x向右移动k位,左端补k个0。
- 算术右移:x向右移动k位,左端补k个最高有效位。
整数表示
整型数据类型
- unsigned代表无符号数,无符号数只能是正数。
long类型的数字,在32位字长和64位字长取值范围是不一样的。
无符号数编码
示例:
对于十进制1,编码为0001。对于十进制5,编码为0101…
负数编码
计算机使用补码编码负数。
- 补码计算规则中,最高位为符号位,符号位为1时,表示值为负。符号位为0时,表示值为正。
补码的最大最小范围是不对称的,对于一个4位的二进制补码来说。最大值是0111=7,最小值是1000=-8。
有符号数和无符号数之间的转换
C 语言运行各种不同的数字数据类型做强制类型转换。
转换规则:类型转换的结果保持位值不变,只是改变了解释这些位的方法。
C语言中的有符号数与无符号数
几乎所有的机器都使用补码标识有符号数。
- 大多数声明默认都是有符号的,需要特指无符号,需要加上后缀‘u’。
当执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么C语言会隐式地将有符号数转化为无符号数,来执行这个运算。
扩展数字位
无符号数据类型的零扩展:扩展位添加0。比如unsigned char 8位,扩展到unsigned short b 16位,需要在最左端补8个零即可。
有符号数据的符号扩展:扩展位添加最高有效位。这样补码数值即可保持不变。
截断数字
截断无符号数:x(截断后) = x(截断前)mod2^k ,k代表截断的位数。
截断补码数值: x(截断后) = (x(截断前)mod2^k)->求补码 ,k代表截断的位数。
整数运算
无符号数加法
```c //这个例子,输出的结果是0,因为255+1=256 超过了unsigned char 代表的数字范围。 int main(){ unsigned char a = 255; unsigned char b = 1;
unsigned char c = a+b; printf(“c=%d”, c);
}
- ![image.png](https://cdn.nlark.com/yuque/0/2022/png/2172986/1658549683454-becbd954-458e-4285-85c5-b135fe567f2e.png#clientId=ubd085656-fa84-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=83&id=u88144108&margin=%5Bobject%20Object%5D&name=image.png&originHeight=166&originWidth=926&originalType=binary&ratio=1&rotation=0&showTitle=false&size=102725&status=done&style=none&taskId=ua9c8fb28-60e9-434b-9b45-464f9c26f88&title=&width=463)
<a name="FwpGB"></a>
### 有符号数加法
```c
//127+1=128 有符号数加法,发生了正溢出,所以128要减去256=128
int main(){
char x = 127;
char y = 1;
char z = x+y;
printf("z=%d", z);
}
- 和无符号数不同,有符号数区分了正溢出和负溢出。
-
补码的非
-
无符号乘法
C语言中的无符号乘法被定义为产生w位的值(乘法最高会产生2w位的值),这就会产生截断,所以无符号数乘法会使用取模运算。
-
有符号数乘法
计算的前面步骤和有符号数一致,只不过最后需要转补码。
-
乘法运算
特殊情况:乘以2,代表x<<1。乘以2^2,代表x<<2。乘以2^k,代表x<<k。以此类推。
依次类推:比如x14, 14=2^3+2^2+2^1,x14 = x<<3 + x<<2+x<<1。这样,一个乘法操作,就可以转化为3个左移操作相加。
除法运算
运算步骤和乘法运算类似,不过除法运算采用的是右移动。
-
2.4 浮点数
二进制小数表示
使用表示二进制小数。符号‘.’变成了二进制的点,点左边的位的权是2的正幂,点右边的位的权是2的负幂。101.11(二进制)=12^2+02^1+12^0+12^(-1)+1*2^(-2)
-
IEEE 浮点表示
- 浮点数的值可以分为三类:规格化的值,非规格化的值,特殊值(无穷大,NAN)
- exp阶码用来区分不同的类别,exp!=0&exp!=255 代表值是规格化的。exp=0代表值是非规格化的。exp=255代表值是特殊值。
- 规格化:阶码数值=exp-bias。bias代表偏置量,bias(float) = 2^7-1 = 127。位数M = 1+frace。
- 非规格化:阶码数值=1-bias。bias代表偏置量,bias(float) = 2^7-1 = 127。位数M = frace。
特殊值:当frac小数位全为0时,如果s=0,代表正无穷大。如果s=1,代表负无穷大。如果frac!=0,代表NaN。
舍入
向下舍入:总是朝着最小的方向进行舍入。
- 向上舍入:总是朝着最大的方向进行舍入。
- 向偶数舍入:也被称为向最近的值舍入,1.4 最接近1,向1舍入。1.6最接近2,向2舍入。如果处于中间值,比如1.5,可以舍入2 或者1,这个时候就要向偶数舍入,因此应该舍入2。
向零舍入:正数进行向下舍入,把负数进行向上舍入。舍入都是朝零方向。
浮点运算
(3.14+1e10)-1e10 = 0.0,表达式对(3.14+1e10)进行计算时,会对结果进行舍入,3.14会丢失,所以得到结果0