《CSAPP》 位移运算+机器中的整数表示(第二章)

前言

最近终于把毕业论文弄完了,一遍遍的修改格式,打印,准备答辩PPT,预答辩,然后拍了毕业照,接下来要忙的就是论文装订,档案审核,毕业季真是忙的要命啊!
要读的书也因为毕业的事情搁浅了一段时间,现在拾起来。

C语言中的移位运算

C语言中移位运算分为向左移和向右移。

  1. 逻辑左移和算术左移操作是一样的,不管是有符号数和无符号数,都是在后边补0。
    【举例】
    01100011 逻辑左移<<4:00110000 算术左移<<4:00110000
    10010101 逻辑左移<<4:01010000 算术左移<<4:01010000

  2. 逻辑右移在最高位补0,算术右移在高位补相应的高位数值(一般有符号数就默认算术右移)。
    【举例】
    01100011 逻辑右移>>4:00000110 算术右移>>4:00000110
    10010101 逻辑右移>>4:00001001 算术左移>>4:11111001

整数表示

这里首先介绍了各个数据类型(有符号数和无符号数的char、int等)的最大值与最小值,这里不再贴出来了。

  1. 无符号数的编码
    简单来说,就是二进制表示方法,由0,1组成。
    函数B2Uw:Binary to Unsigned,长度为w二进制数的无符号表示(二进制到无符号数)。
    (1)无符号数编码的定义
    一个w位的二进制无符号数,B2Uw函数能从位相量映射到整数。
    【举例】
    B2U4([0001])=0*2^3+0*2^2+0*2^1+1*2^0=0+0+0+1=1
    B2U4([1011])=1*2^3+0*2^2+1*2^1+1*2^0=8+0+2+1=11
    给出一个十进制数,就能得出唯一一个二进制数。
    每个介于0~2^w-1之间的数都有唯一一个w位的值编码。(无符号编码具有唯一性)

  2. 补码编码
    常见的有符号数的计算机表示方法就是补码(two’s-complement)形式。
    函数B2Tw:Binary to Two’s-complement,长度为w。(二进制到补码形式)
    最高有效位即为符号位,它的“权重”为-2^w-1。
    【举例】
    B2T4([0001])=-0*2^3+0*2^2+0*2^1+1*2^0=0+0+0+1=1
    B2T4([1011])=-1*2^3+0*2^2+1*2^1+1*2^0=-8+0+2+1=-5
    补码编码也具有唯一性。

  3. 有符号数和无符号数之间的转换
    有符号数和无符号数之间可以进行强制类型转换。
    将负数转换成无符号数可能会得到0,如果需要转换的无符号数太大,超出了补码能够表示的范围,可能会得到TMax。
    【举例】有符号数转换成无符号数
    (unsigned short)-12345=53191,即T2U16(-12345)=53191
    这里保持位值不变,只是改变了解释这些位的方式。因为-12345和53191的二进制表示是一样的。
    规则:数值可能会变,但是位模式不变。
    函数T2Uw,定义为T2Uw(x)=B2Uw(T2Bw(x))。这个函数的输入是一个TMinw~TMaxw的数,结果得到一个0~UMaxw的值。
    函数U2Tw,同上,U2T16(53191)=-12345,十六进制表示写作0xCFC7的16位位模式既是-12345的补码表示,又是53191的无符号表示。同时12345+53191=65536=2^16。

  4. C语言中的有符号数和无符号数
    通常大多数数字都默认是有符号的,要创建一个无符号常量时,必须加上后缀字符‘U’或者‘u’,例如12345U或者0x1A2Bu。
    printf输出数值时,分别用指示符%d、%u、%x分别表示有符号十进制、无符号十进制和十六进制格式输出一个数字。

  5. 扩展一个数字的位表示
    一个常见的运算是在不同字节的整数之间转换,同时又保持数值不变。
    零扩展:将一个无符号数转换为一个更大的数据类型,只要简单地在表示的开头添加0即可。
    符号扩展:将一个补码数字转换为一个更大的数据类型,在表示中添加最高有效位的值。(因为是补码的形式,转换为原码后,再计算,值是一样的。)

  6. 截断数字
    减少表示一个数字的位数。
    int->short。将32位的int截断成了16位的short int。
    截断无符号数:
    截断k位,即把高w-k位丢弃,从左到右前k位。
    截断符号数:
    先用无符号数截断后表示,再转换为补码形式即可。

  7. 存在的漏洞
    已经看到了许多无符号数运算的细微特性,尤其是有符号数到无符号数的隐式转换,会导致错误或者漏洞。避免这类错误的一种方法就是绝不使用无符号数。

文章目录
  1. 1. 前言
    1. 1.1. C语言中的移位运算
    2. 1.2. 整数表示