深入理解计算机系统(CSAPP) 实验详解:DataLab
更新历史
20200911
开始做这个实验20200915
更新文章-题目更新到isTmax20200918
更新文章-题目更新到isAsciiDigit20200927
更新文章-题目更新到isLessOrEqual- 停止更新
该实验的目的
该实验的目的是提升对计算机基础信息的理解和操作,例如位,整数,浮动,补码等等。
搭建环境
环境的搭建很简单,我们遵循以下几个步骤即可
- 下载VM Box,并安装ubuntu
- 然后我们在虚拟机中更新环境,在终端中执行一下命令
//更新apt软件源
apt-get update
//安装sudo
apt-get install sudo
//安装c/c++编译环境,build-essential软件包列表内包含libc6-dev、libc-dev、gcc、g++、make、dpkg等
sudo apt-get install build-essential
//补充gcc的完整环境(gcc-multilib)
sudo apt-get install gcc-multilib
//安装gdb
sudo apt-get install gdb
- 然后我们就可以愉快的写代码了,你可以使用VS Code
如何使用正确的姿势写代码和测试
主要是一下几个步骤:
- 阅读
bits.c
的注释,然后在代码处修改它 - 命令行运行
./dlc -e bits.c
查看自己用了多少操作符,以及是否有代码风格问题 - 使用终端,执行
make clean && make btest
编译文件 - 使用终端,执行
./btest
,检查自己是否做对了 - 最终运行
./driver.pl
获得打分
下面是对主要文件的解释:
- bits.c:这个是题目文件,也是我们写代码的地方,同时里面包含着各种要求,做题时需要仔细查看该题的限制。
- btest.c:测试代码的工具,编译它(使用终端
make btest
)我们可以获得可执行文件,执行它会对你的代码进行测试,注意每次修改完代码之后都需要重新编译btest.c
。上面显示了你哪些题目通过测试了,哪些题目没有通过测试,同时也给出了没有通过测试的原因。 dlc(data lab compiler)
:
实验开始
采用以下框架来记录
- 题解(题目解读)
- 代码(包含注释)
- 思路
- 对于本次实验的思考和总结
bitXor
题解:
只用~和&实现一个异或门
//1
/* * bitXor - x^y using only ~ and & * Example: bitXor(4, 5) = 1* Legal ops: ~ &* Max ops: 14* Rating: 1*/
int bitXor(int x, int y) {return 2;
}
思路:
在解这道题目的时候我首先想到的是在《编码》当中实现的异或门
,异或门
是由三个逻辑门构成的,分别是与门
,或门
,非门
构成的。如下图所示
而在这个题目当中,限制了我们使用或门
,使得我们不得不自己使用与门
和非门
组合成一个或门
。
然而要想实现一个或门
我们就得先观察或门
的关系表
Or | 0 | 1 |
---|---|---|
0 | 0 | 1 |
1 | 1 | 1 |
“对一个
与门
进行非操作,可以得到或门
”
这个其实是我对与门
的关系表观察得到的,因为与门
与或门
之间貌似是一个互补关系,或门
为1的情况出现了三次,与门
出现了一次,而且刚刚好与门
出现的1的情况就在角落里,想象一下要是我可以旋转一下1值出现的地方,在进行非操作,那么不就可以得出一个或门
了么。经过尝试,确实是可以的。演变的过程如下图
图图图图,后面补上
那么将这个过程转化为代码就是下面的样子
~(~x&~y)// | = ~(~x&~y)
然后再根据上面的分析,转化为代码
|&(~(x&y))
// 将|替换
(~(~x&~y))&(~(x&y))// 这个就是我们题目的答案了//1
/* * bitXor - x^y using only ~ and & * Example: bitXor(4, 5) = 1* Legal ops: ~ &* Max ops: 14* Rating: 1*/
int bitXor(int x, int y) {return (~(~x&~y))&(~(x&y));
}
最后贴上一张异或门的图
这道题很有意思,建议自己也去实现或门
和异或门
电路模拟
tmin
题解:
返回2进制的最小值
/* * tmin - return minimum two's complement integer * Legal ops: ! ~ & ^ | + << >>* Max ops: 4* Rating: 1*/
int tmin(void) {return 2;}
思路:
0x8000 0000
是16进制表示法,将16进制转化为二进制,我们就可以得出该答案了,即
/* * tmin - return minimum two's complement integer * Legal ops: ! ~ & ^ | + << >>* Max ops: 4* Rating: 1*/
int tmin(void) {return 0x1<<31;}
isTmax
题解:
检查是否是有符号数的最大值
//2
/** isTmax - returns 1 if x is the maximum, two's complement number,* and 0 otherwise * Legal ops: ! ~ & ^ | +* Max ops: 10* Rating: 1*/
int isTmax(int x) {return 2;
}
思路:
这道题目和上一题的获取最小值有一点点小关系,我们要和最大值比较,那么肯定得获取到最大值,最大值的表示方法0x1<<31 - 1
,然后我们就和输入值比较即可。但是题目是有限制的,不允许使用<<
。那么我们只能换一种思路了。
机器在判断的时候,一个非零布尔值的都是true
根据上面的结论,我们需要判断给定值x
判断是否为补码最大值,那么就需要经过某种特定的步骤把它转化为零。我们继续观察上图,发现最大值和最小值相加会等于一个特殊的值,即0xFFFF FFFF,用二进制表示它会是全一
,取反之后就是全零
。
int i = x+1;// 这里我们取极端情况,当x就是最大值的时候,加一就变为最小值,看上面的图得出
x = x + i;// 最大值+最小值得到全一,0xFFFF FFFF
x = ~x;// 取反得全零。0x0000 0000
return !x;// 得到的结果是相反的,所有我们还得!一下。
然而到这里还没有结束,看上图,我们发现最后面的0xFFFF FFFF
,它也是特殊情况之一,它加一等于全零
了,而他本身是全一
的情况,所以我们还得排除这个0xFFFF FFFF。到此我们的答案就出来了~
i = !i;// 给i取反,上面结论说了,一个非零的布尔值都是true,也就是1
x = x + i;// 所以当我们给x+i的时候,要么加0要么就加1,它就会影响到下面的结果//2
/** isTmax - returns 1 if x is the maximum, two's complement number,* and 0 otherwise * Legal ops: ! ~ & ^ | +* Max ops: 10* Rating: 1*/
int isTmax(int x) {int i = x+1;// 这里我们取极端情况,当x就是最大值的时候,加一就变为最小值,看上面的图得出x = x + i;// 最大值+最小值得到全一,0xFFFF FFFFx = ~x;// 取反得全零。0x0000 0000i = !i;// 给i取反,上面结论说了,一个非零的布尔值都是true,也就是1x = x + i;// 所以当我们给x+i的时候,要么加0要么就加1,它就会影响到下面的结果return !x;// 得到的结果是相反的,所有我们还得!一下。
}
allOddBits
题解:
判断在二进制表示中奇数位是否全为一
/* * allOddBits - return 1 if all odd-numbered bits in word set to 1* where bits are numbered from 0 (least significant) to 31 (most significant)* Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1* Legal ops: ! ~ & ^ | + << >>* Max ops: 12* Rating: 2*/
int allOddBits(int x) {return 2;
}
思路:
0xAA代表的是1010 1010,所以我们将8个A拼起来就行了
* allOddBits - return 1 if all odd-numbered bits in word set to 1* where bits are numbered from 0 (least significant) to 31 (most significant)* Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1* Legal ops: ! ~ & ^ | + << >>* Max ops: 12* Rating: 2*/
int allOddBits(int x) {int mask = 0xAA + (0xAA<<8);mask = mask + (mask<<16);return !((mask&x)^mask)
}
isAsciiDigit
题解:
这道题目是让你判断一个数是否在一个区间(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) {return 2;
}
思路:
假如我们要判断的3-9
这个区间,想要判断某个数和另外一个数的大小,简单的方法是通过减法,然后在通过正负号去判断。
上面的(3-1)
是因为我们要包含3-3=0x0
的情况,因为我们的题目是含有等于的。
回到我们的题目中,两个极值,或者叫边界值结合起来,它们需要共同满足图中的等式即
0x2F+(~x+1)=0x1
0x39+(~x+1)=0x0
转化为代码即
//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 min = 0x2F+(~x+1);int max = 0x39+(~x+1);min = !!(min >> 31);// 我们是通过符号位来判断的 所以将符合号位右移31位,同时将结果都转化为truemax = !(max >> 31);// 这个也需要将结果转化为true,这样下面我们才能通过与运算来确定我们要的结果return min & max;
}
isLessOrEqual
题解:
实现一个小于等于符
/* * 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) {return 2;
}
思路:
这道题是让我们实现一个一个小于等于符号,判断两个数的大小分两种情况
- 符号位相同,通过做差,然后在通过符号位判断。
- 符号位不相同,可以直接判断
x
的符号位。
第一种情况:
如果我们直接让x-y
做差,那么会有三种结果
- 差值小于零,符号位为一
- 差值等于零,符号位为零
- 差值大于零,符号位为零
那么这三种,是无法满足题目需求的,题目要求是小于等于,通过x-y
小于和等于零时符号位是相反的。我们知道x<=y
其实也等于y>=x
,那么这种情况刚刚就满足第二和第三种情况,大于等于零的时候符号位是相同的。由此可以得出y+(~x+1)
,同时我们将右移加上,得到符号位
!(y+(~x+1)>>31)// 取非是因为我们的结果是零,题目要求返回1
第二种情况:
我们只需要判断符号位是否相同即可
x>>31 ^ y>>31;// 相同为零
两种情况结合:
两种情况结合的话我们需要用到mask
,用来选择当另外一种情况成立时,把另外一种情况给消除掉。刚刚好我们的第二种情况就给我们提供了这样的条件。通过判断符号位,当符号位相同时,我们就将mask
设置为全零,当符号位不相同时,设置mask
为全一,即完成所有的代码。
/* * 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 test = !(y+(~x+1))>>31;// < 0,> 1,= 1int checkSign = x>>31 ^ y>>31;// equip 0int maskSign = ~(~checkSign+1);//0->1,1->0return (~maskSign&(x>>31 & 0x1))|(maskSign&test);//(x>>31 & 01)直接比较符号位
}
未完成,待续~
深入理解计算机系统(CSAPP) 实验详解:DataLab相关推荐
- 深入理解计算机系统(CSAPP) 实验详解:CacheLab
近一段时间项目太忙导致没有继续,还好最近空下来一些,咱们继续冲! 更新历史 20210104开始更新 20210107完成实验一内容 本文介绍的是CSAPP书籍中的第四个lab: Cache lab. ...
- STM32F429第二十五篇之MCU屏实验详解
文章目录 前言 硬件 软件 结构体 SRAM_HandleTypeDef Instance(FMC寄存器地址) Extended(拓展寄存器地址) Init(初始化变量) Lock(锁) State( ...
- CSAPP之详解Labs
CSAPP-labs-RECORD 前言 读万卷书,不如行万里路.如果你读到了这本书,可千万不要错过本书的配套实验. 其中几个纵享盛名的实验,分别是: BombLab MollocLab ShellL ...
- 实验详解——Cobbler自动部署最小化安装
实验详解--Cobbler自动部署最小化安装 一.实验:自动部署 二.Cobbler自动装机服务搭建步骤 1.导入epel源并加载在线安装源 2.安装Cobbler以及其相关服务软件包 3.修改cob ...
- 实验详解——DNS网关服务器的分离解析
实验详解--DNS网关服务器的分离解析 一.实验图 二.要求 三.实验开始 1.网关服务器的配置 ①.新添加一块网卡,用双网卡来演示网关服务器的两个端口 ②.对两个网卡进行配置的修改 ③.重启网卡并查 ...
- 实验详解——DNS反向解析、DNS主服务器和从服务器的配置
实验详解--DNS反向解析.DNS主服务器和从服务器的配置 实验一:DNS反向解析 1.安装bind 2.查找配置文件路径 3.配置/etc/named.conf主配置文件 4.修改/etc/name ...
- 详解FTP服务完成Linux和WIN10之间的信息传输(实验详解)
详解FTP服务完成Linux和WIN10之间的信息传输(实验详解) 一.FTP简介 1. FTP服务--用来传输文件的协议 2.端口 3.数据连接模式 二.相关配置 1.安装FTP服务 2.设置匿名用 ...
- 详解 Linux环境中DHCP分配IP地址(实验详解)
Linux中DHCP小实验详解 一.DHCP中继概述 二.DHCP在linux系统中的相关配置 1.配置DHCP服务器 2.设置全局配置参数 3.subnet网段声明 4.host主机声明 三.实验例 ...
- 实验详解——parted单磁盘分区并进行配额
实验详解--parted单磁盘分区并进行配额 一.实验要求 二.实验开始 1.添加新硬盘 2.对新硬盘进行parted分区,格式设置为ext4 3.格式化分区,格式为ext4 4.设置配额方式和挂载 ...
最新文章
- 普度网络营销策划_普度网络营销策划-齐宁_新浪博客
- 狼羊菜过河问题深入学习分析——Java语言描述版
- 操作系统 ——进程的状态与转换
- 做自媒体和有没有文化没有太大关系
- 问题十一:用条件编译(#if…#endif)避免 main函数中测试代码在测试完成后就删除
- android Xmpp+openfire 消息推送 :SASL authentication failed using mechanism DIGEST-MD5
- 【通信】基于matlab语音信号仿真【含Matlab源码 957期】
- ROS实战篇(一)如何在ROS中编写自己的package?------ 以节点通信为例
- Android中铃声总结源码
- stm32学习探究:利用TB6612驱动直流电机
- 盘点前端开发常用的几款编辑器
- IDEA教育版申请流程
- 高效办公之高效学习技巧:艾宾浩斯遗忘曲线及学习策略分享
- OAuth 2.0 授权认证详解
- python计算纪念日相关
- 基于 Vue 实现 Excel 的解析与导出
- java poi 导入报错,Cannot get a NUMERIC value from a STRING cell
- 计算机研究生搞理论出来找工作,一个计算机专业研究生的迷茫
- ITIL学习笔记——核心流程之:容量管理
- 手机android的文件怎么恢复,安卓手机怎样恢复删除的文件