CSAPP_Lab0_环境配置
Docker 让你省去配置环境的烦恼
搜索 CSAPP:什么:环境配置竟然这么简单
WSL2
也很方便,省去了找Docker镜像,Vscode配置到本地端口等麻烦
前置知识
逻辑移动 Logic Shift
如图,一个字节的数据向右移动一位,空出来的位用0填充
11001111逻辑右移一位,最低位进入进位标识位
算术移动 arithmetic shift
11001111,符号位为1,算术右移一位后得到11100111:
SHL
SHL(左移)指令使目的操作数逻辑左移一位,最低位用 0 填充。最高位移入进位标志位,而进位标志位中原来的数值被丢弃:
若将 1100 1111 左移 1 位,该数就变为 1001 1110:
SHL 的第一个操作数是目的操作数,第二个操作数是移位次数:
SHL destination,count
该指令可用的操作数类型如下所示:
SHL reg, imm8 SHL mem, imm8 SHL reg, CL SHL mem, CL
x86 处理器允许 imm8 为 0〜255 中的任何整数。另外,CL 寄存器包含的是移位计数。上述格式同样适用于 SHR、SAL、SAR、ROR、ROL、RCR 和 RCL 指令。
[示例]下列指令中,BL 左移一位。最高位复制到进位标志位,最低位填充 0:
mov b1, 8Fh ; BL = 10001111b shl bl, 1 ; CF = 1, BL = 00011110b
当一个数多次进行左移时,进位标志位保存的是最后移岀最高有效位(MSB)的数值。下例中,位 7 没有留在进位标志位中,因为,它被位 6(0)替换了:
mov al, 10000000b shl al, 2 ; CF = 0, AL = 00000000b
同样,当一个数多次进行右移时,进位标志位保存的是最后移出最低有效位(LSB)的数值。
位元乘法
数值进行左移(向 MSB 移动)即执行了位元乘法(Bitwise Multiplication)。例如,SHL 可以通过 2 的幕进行乘法运算。任何操作数左移 n 位,即将该数乘以 2n。现将整数 5 左移一位则得到 5 x 2¹ = 10:
mov dl, 5 ; 移动前:00000101 = 5 shl dl, 1 ; 移动后:00001010 = 10
若二进制数 0000 1010(十进制数 10)左移两位,其结果与 10 乘以 2² 相同:
mov dl, 10 ;移动前:00001010 shl dl, 2 ;移动后:00101000
SHR
SHR(右移)指令使目的操作数逻辑右移一位,最高位用 0 填充。最低位复制到进位标志位,而进位标志位中原来的数值被丢弃:
SHR 与《SHL指令 》一节中介绍的 SHL 的指令格式相同。在下面的例子中,AL 中的最低位 0 被复制到进位标志位,而 AL 中的最高位用 0 填充:
mov al, 0D0h ; AL = 11010000b shr al, 1 ; AL = 01101000b, CF = 0
在多位移操作中,最后一个移出位 0(LSB)的数值进入进位标志位:
mov al, 00000010b shr al, 2 ; AL = 00000000b, CF = 1
位元除法
数值进行右移(向 LSB 移动)即执行了位元除法(Bitwise Division)。将一个无符号数右移 n 位,即将该数除以 2n。下述语句将 32 除以 2¹,结果为 16:
mov dl, 32 ;移动前:00100000 = 32 shr dl, 1 ;移动后:00010000 = 16
下例实现的是 64 除以 2³:
mov al, 01000000b ;AL = 64 shr al, 3 ;除以 8, AL = 00001000b
用移位的方法实现有符号数除法可以使用 SAR 指令,因为该指令会保留操作数的符号位。
函数实现
int isAsciiDigit(int x)1
该函数判断一个数是不是在[0x30,0x39],
//3
/*
* isAsciiDigit - return 1 if 0x30 <= x <= 0x39
(ASCII codes for characters '0' to '9')
* Example: isAsciiDigit(0x35) = 1.
* isAsciiDigit(0x3a) = 0.
* isAsciiDigit(0x05) = 0.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 15
* Rating: 3
*/
int isAsciiDigit(int x) {
int mask=(0x1<<31);
int lessthan=x+~0x30+1;
int morethan=0x39+~x+1;
int less=lessthan&mask;
int more=morethan&mask;
return !(less|more) ;
}
isLessOrEqual()2
/*
* isLessOrEqual - if x <= y then return 1, else return 0
* Example: isLessOrEqual(4,5) = 1.
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 24
* Rating: 3
*/
int isLessOrEqual(int x, int y) {
int mask =0x1<<31;
return (!!((x+~y+1)&mask))|!(x+~y+1); //this is wrong!😫
}
正确的3
int isLessOrEqual(int x, int y) {
int temp=x+~y+1;
int flag=temp>>31;
int flag_x=x>>31;
int flag_y=y>>31;
return !!( (flag&(flag_x|!flag_y))|(!flag&(!(temp^0x0)|(flag_x&(!flag_y)))));
}
//😫 gross,我自己都不愿再去看自己写的这个return,AB+AC,本以为能优化,可惜优不得,也懒得去看别人的,摆烂
logicalNeg
/*
- logicalNeg - implement the ! operator, using all of
- `the legal operators except !`
- Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
- Legal ops: ~ & ^ | + << >>
- Max ops: 12
- Rating: 4
*/
int logicalNeg(int x) {
return ~(x|(~x+1))>>31&1;
}
//😚😚,然然我真的好喜欢你啊,我要写csapp lab!反转了写不出来,你带我走吧
突然反应过来有些本来就是0x00000001的不需要再!!()来强制转换成1了。。。。。
还想了一小会儿,非0数的正负肯定会导致符号位不一样啊。但是直接哟x|~x+1,要明白不光有一正一负,
负数 即 0|0→0
这种0|1→1,也有Tmin,-Tmin仍然是Tmin啊!不过很巧很巧,1|1→1,当且仅当x为0时才会让x和-x都为负数