CSAPP Datalab

最近慢慢开始看CSAPP了,学完了前两章来做个lab巩固一下前面所学的知识。

该篇博客用于记录从零开始完成CSAPP datalab。

环境准备

  • 我一开始配置的是VMware虚拟机及建了一个CentOS7操作系统虚拟机。(后面发现在CentOS7上面有点麻烦,重新建了一个ubuntu操作系统)

  • VMware虚拟机的配置我是之前看的Linux网课配置的,可以去自行寻找资源配置

  • 关于unbuntu的配置可以参考这篇博客ubuntu的配置

  • 配置好ubuntu后在虚拟机打开终端执行以下命令(若遇bug参考下面注意)

apt-get update								更新apt软件源
sudo apt-get install build-essential		安装C/C++编译环境
sudo apt-get install gcc-multilib			补充gcc完整环境
sudo apt-get install gdb					安装gdb

注意:

在虚拟机打开终端执行上面操作时,有一个小细节,给我包括我其他的同学都造成了一点障碍。

我们可能会因为权限不够问题无法执行上述指令,这时可以通过su指令将前面的$(普通终端用户)变为#(超级用户),如果你前面的符号成功变为#,那么恭喜你,下面的这些内容你可以跳过了,但如果你和我一样出现了以下问题:

在这里插入图片描述

那么你就可以去参考一下报错su:认证失败这篇文章了。


接下来就可以去官网CS:APP3e, Bryant and O’Hallaron (cmu.edu)下载datalab-handout开始操作了。

在这里插入图片描述

下载的文件如下图所示:

在这里插入图片描述

我们的目标是修改bits.c文件中的内容,使其通过btest中的所有测试,且同时不违反任何编码准则。

需要注意的是我们操作的是bits.c文件里的代码,完成代码后保存,要在datalab-handout文件下在终端打开,执行以下指令就可以查看我们的得分以及答案是否正确了

make && ./btest

当我们执行make && ./btest出现以下形式时,即配置好了

在这里插入图片描述

下面我们就开始动手做题吧。

1.bitXor

本题要求是让我们通过~和&实现异或。首先我们要知道什么是异或,异或就是对于两个数x,y,相等时为0,不等时为1,用x^y表示异或运算。

学过离散数学的都知道,x⊕y = (¬x ∧ y) ∨ (x ∧¬y)=¬(¬(¬x ∧ y)∧¬(x ∧¬y)),没有学过的可以自行百度学一下哈哈哈。

所以答案就是

return ~(~(~x&y)&~(x&~y));

2.tmin

本题要求我们返回二进制形式下,补码表示的最小int值。在本实验int是4个字节,故用32位表示。此时Int的最小取值为-2^31,用补码表示,只需将1左移31为。

故答案为

return (1<<31);

3.isTmax

本题让我们判断x是不是二进制形式下补码表示的最大数。如果是,返回1。不是,返回0。(建议先理解第五题再来做这道题)

先理解~x+1与(~x)+1的区别。

我们对tmax取反后发现,它就是tmin,而tmin有个特征,就是tmin取反就是它本身,通过tmin^(~tmin+1)从而就能判断这个数是不是tmax,但要注意的是,0取反也是它本身,只需再特判一下。

故本题答案为

x=~x;
return !(x^(~x+1)) & (!!x);

x如果是0,!!x就为0;x如果为其他任意常数,!!x就为1,从而可以特判x是否为0。

4.allOldBits

本题让我们判断给定的二进制数,是不是全部的奇数位都为1(如10101010)。

我们只需将给定的数&上1010…1010,看最后得到的答案满不满足条件即可。

int old1=0xAA;//10101010
int old2=(old1<<8)+old1;//1010101010101010
int old3=(old2<<16)+old2;//10101010101010101010101010101010
return !((old3&x)^old3);

5.negate

本题要求返回一个数的相反数。在二进制补码中,取反加1就是其相反数。

故答案为

return (~x)+1;

6.isAsciiDigit

本题让我们判断一个数是否位于0x300x39之间。在时返回1,不在返回0。

要做本题,我们需要先了解一下掩码运算(CSAPP原书38页)。大致思路为先判断10位是否为3,再判断个位是否小于等于9。关于如何判断个位是否小于等于9,我们应该知道要判断y>=x,只需判断y+(-x)>=0,故我们要判断a是否小于等于9,只需判断9+(-a)>=0,可以通过移位操作得到这个数的符号位,从而来判断一个数是否大于0。

int y=x&0xf;//掩码运算得到x的个位
return !((x>>4)^0x3) & !((0x9+(~y+1))>>31);

7.conditional

本题让我们实现x ? y : z,即x不为0时返回y,为0时返回x。

x=0时我们可以通过(0xfffffff&y)|(0x00000000&z)来得到答案 ,同时x!=0时我们可以通过(0x00000000&y)|(0xffffffff&z)来得到答案。故我们只需要判断x是否等于0再来判断是0xfffffff&y还是0x00000000&y。

int checkZero=!!x;//x=0,checkZero=0;x!=0,checkZero=1
int check=~checkZero+1;//checkZero=0,check=0x00000000;checkZero=1,check=0xffffffff
return (check&y)|(~check&z);

8.isLessOrEqual

本题让我们判断x<=y。只需分别判断同号和异号时的情况。

异号时要判断y>=x,操作和第六题我们判断个位数是否小于等于9一样。

int checkx=x>>31;//判断x的正负
int checky=y>>31;//判断y的正负
int checkxy=checkx^checky;//判断x,y是否异号
int xx=~x+1;
return (checkx&checky&!checkxy)|(!checkxy&!((y+xx)>>31));

9.logicalNeg

本题让我们实现!运算,也就是x=0时返回1,否则返回0。我们只需要知道只有0与其相反数或后,所有位才为0。正数负数的相反数必为负数或正数,符号位必不同,或之后符号位必为1。

return ((x|(~x+1))>>31)+1;

10.howManyBits

本题要求我们返回一个数在二进制补码的表达形式下,最少需要多少位才能表达出来。

要做本题,我们要清楚以下结论:

当x为正数时,假设y表示1的最高位置,该数需要y+1位表达出来;如果x为负数时,将x取反,假设y表示1的最高位置,该数需要y+1位表达出来。

所有我们可以通过找最高的1的位置来确定答案。不能使用循环,所以我们采取二分的方式来操作。

int b16,b8,b4,b2,b1,b0;
  int signX = x>>31;
  x = ((~signX) & x) | (signX&(~x));
  b16 = (!!(x>>16))<<4; 
  x=x>>b16;
  b8 = (!!(x>>8))<<3;
  x=x>>b8;
  b4 = (!!(x>>4))<<2;
  x=x>>b4;  
  b2 = (!!(x>>2))<<1;
  x=x>>b2; 
  b1 = !!(x>>1);
  x = x>>b1;
  b0 = x;
  return b0+b1+b2+b4+b8+b16+1;
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值