NJU-OSlab0(2)-vfprintk的实现

之前已经将初始化工作说明完毕,这次开始完成实验要求。

实验要求如下:

响应键盘中断

我们给出的框架代码并没有响应键盘中断, 你需要在理解框架代码的基础上, 补充代码来实现相应的功能. (Hint: 按下键盘后, 中断控制器给CPU发送的中断号是33)
代码中已经实现了时钟中断的响应, 可以帮助你理解中断机制相关的代码.
功能实现之后, 你会得到一款完整的打字游戏.
首先来看下框架代码:
NJU-OSlab0(2)-vfprintk的实现_第1张图片
我们首先来看printk函数。
printk函数的参数是可变个数的,函数形参是从右往左依次入栈,所以args[0]访问第一个左边参数,args[1]访问左边第二个参数啦。
不过这些入栈的参数都是什么呢?是参数本身还是其它的什么呢?我做了两个猜测:

猜想

  • 第一种猜测,存入的是指向参数的指针,证据如下:因为参数数组是void **,说明每个参数也就是void *了,也就是指针对吧
  • 第二种猜测,存入的是参数本身,比如int,直接就可以存入int,因为sizeof(void *) = sizeof(int) = 4,而字符串则存入char *,char存入char本身,但因为它只有1个字节,为了字节边界对齐,所以要补足成4个字节。

假如是第一种猜测。

那么按照这里函数写的,入栈的应该都是参数的指针,比如对于printk(“%d, %s, %lf”, 1, “ab”, 3.1),在栈中存储情况如下图所示。首先入栈double3.1的指针,之后入栈”ab”的指针,接着入栈int1的指针,最后入栈”%d,%s,%lf”的指针。此时栈顶地址便是(void **)&ctl。
NJU-OSlab0(2)-vfprintk的实现_第2张图片
下面做实验来验证下吧:
实现vfprintk的思路便是遍历ctl查看命令,查看到%之后根据指定参数从args中找到参数地址,得到参数,之后再输出就好啦。

结果如下,红框中的是%c测试,绿框中的是%d测试,都不成功呢:
NJU-OSlab0(2)-vfprintk的实现_第3张图片

那么按照第二种猜想进行实验

代码如下:
这个是16进制转换
NJU-OSlab0(2)-vfprintk的实现_第4张图片
这个是int转字符串


NJU-OSlab0(2)-vfprintk的实现_第5张图片
结果ok啦,哈哈,可口可乐yeah!

如果不想采用args指针自增的方式,将args看做数组,用数组访问方式也是ok的,代码修改如下,修改绿框中的内容就好了:
NJU-OSlab0(2)-vfprintk的实现_第6张图片
- %s的实现只需要遍历char *,一个个的输出就好了
- %d的实现是将int转化为char []数组,之后输出char数组,一般的想法都是先判断int正负,如果为负,将负号提出,再转为正数,然后依次取每一位存起来。不过这里有个问题哦:
- 4字节int的范围是-2147483648~2147483647,所以-2147483648转为正数2147483648是超过了int的表示范围的,怎么办呢?用unsigned int。
- %c的实现关键在于如何从得到的四个字节信息中取出属于char的那个字节
int的四个字节是如何存放的呢?用int转char得到的会是哪个字节呢?我做了个小实验:

从结果中可以看出在栈中int的存储是低位地址存储低字节,高位地址存储高字节信息,且int的起始地址是最低的0x12ff28 = &i。
int转char得到的也是int地址开始的8位信息,也就是最低字节。
NJU-OSlab0(2)-vfprintk的实现_第7张图片
- %x的实现我一开始是想要用char来获取它的四个字节,然后得到char的高4位和低4位,转化为0~9,a~f的表示,不过这个编译器居然连(>>4)这样的移位操作都提示错误,坑爹呀!!
最后想到的办法就是用unsigned int来表示,不管正负,直接用16去除就是啦,最后得到正确结果,开心呀O(∩_∩)O哈哈~!

vfprintk暂时就先做到这里,其它的表示会在之后陆续增加啦!

最后来提交到git里边吧。
git commit;
git log;
可以看到我的最新提交啦:

你可能感兴趣的:(操作系统相关)