信息存储

  • 计算机使用字节,作为最小可寻找的内存单位,机器级程序将内存视为一个非常大的字节数组,称为虚拟内存,内存的每个字节都由一个唯一的数字来标识,称为地址。所有可能的地址集合,称为虚拟地址空间
  • 每台计算机都有一个字长,34位字长cpu的地址最大范围 0~2^34-1,64位字长cpu的地址范围0~2^64-1,大多数64位机器也可以运行32位机器编译的程序,这是一种向后兼容

    十六进制

  • 计算机使用二进制存储信息,因为二进制表示比较麻烦,引入十六进制表示位模式。

  • 十六进制:简写为hex,范围0-9 a-f 。 十六进制表示法,使用0x开头。比如0x01,0x02。
  • 每4位二进制,可以代表一个十六进制数字。

    字节顺序

  • 几乎所有的机器上,多字节对象被存储为连续的字节序列,对象的地址为使用字节中的最小地址。十六进制0x01234567

image.png

  • 大端法高位字节存入低地址低位字节存入高地址。
  • 小端法低位字节存入低地址高位字节存入高地址。
  • 大端小端依赖于机器类型。如果在不同的机器上进行网络通信,就需要双端统一好字节顺序,避免数据错乱。

    字符串

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

  • 每个字符有编码标准。最常见的ASCII编码。对于中文。需要使用Unicode编码。

    布尔代数

    image.png

  • ^代表异或:相同的元素为0,不同的元素为1

    C语言中的位运算

    image.png

  • ‘|’ 代表或,‘&’代表与,‘~’代表取反,‘^’代表异或

  • 位运算的一个常见用法就是实现掩码运算,比如x=0x89ABCDEF,如果要得到最低有效字节的值,可以使用运算x&0xFF得到。

    C语言中的逻辑运算

  • 逻辑运算认为所有的非零参数都表示为True,而参数零标识False

image.png

C语言中的移位运算

  • 左移:x向左移动k位,丢弃最高的k位,并在右端补k个0。
  • 逻辑右移:x向右移动k位,左端补k个0。
  • 算术右移:x向右移动k位,左端补k个最高有效位。

image.png

整数表示

整型数据类型

image.png

  • unsigned代表无符号数,无符号数只能是正数。
  • long类型的数字,在32位字长和64位字长取值范围是不一样的。

    无符号数编码

  • 示例:image.png

  • 对于十进制1,编码为0001。对于十进制5,编码为0101…

    负数编码

  • 计算机使用补码编码负数。

image.png

  • 补码计算规则中,最高位为符号位,符号位为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);

}

  1. - ![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)
  2. <a name="FwpGB"></a>
  3. ### 有符号数加法
  4. ```c
  5. //127+1=128 有符号数加法,发生了正溢出,所以128要减去256=128
  6. int main(){
  7. char x = 127;
  8. char y = 1;
  9. char z = x+y;
  10. printf("z=%d", z);
  11. }
  • 和无符号数不同,有符号数区分了正溢出负溢出
  • image.png

    补码的非

  • image.png

    无符号乘法

  • C语言中的无符号乘法被定义为产生w位的值(乘法最高会产生2w位的值),这就会产生截断,所以无符号数乘法会使用取模运算

  • image.png

    有符号数乘法

  • 计算的前面步骤和有符号数一致,只不过最后需要转补码。

  • image.png
  • U2T:无符号转补码。

    乘法运算

  • 特殊情况:乘以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 浮点数

    二进制小数表示

  • 使用image.png表示二进制小数。符号‘.’变成了二进制的点,点左边的位的权是2的正幂,点右边的位的权是2的负幂。101.11(二进制)=12^2+02^1+12^0+12^(-1)+1*2^(-2)

  • 某些十进制小数,是无法用二进制小数表示的,比如1/10。

    IEEE 浮点表示

  • image.png

  • image.png
  • 浮点数的值可以分为三类:规格化的值,非规格化的值,特殊值(无穷大,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。

    舍入

    image.png

  • 向下舍入:总是朝着最小的方向进行舍入。

  • 向上舍入:总是朝着最大的方向进行舍入。
  • 向偶数舍入:也被称为向最近的值舍入,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