注:本文档为《从0学x86操作系统》课程配套的学习文档,提供相应的辅助学习资料和答疑勘误。 有关该课程的信息,请点击这里访问:https://study.163.com/provider/1017884735/index.htm 在阅读本文档时,如有疑问和建议,欢迎在下方留言或者直接联系我。

本小节实现了%d、%x、%c的格式化输出,重点在整数转字符串。

主要内容

整数转字符串的函数,在C库中有类似的函数:itoa,参考链接:https://www.cplusplus.com/reference/cstdlib/itoa/?kw=itoa
本课时中实现的功能和它略类似,不过要简单很多,即只支持:%d, %x, %c的转换,不支持设置显示宽度等信息。
在视频中,kernel_itoa的实现有问题,具体为:在将第31位为1的数(例如0x80000000)按%x输出时,生成的字符串不正确。修改后的代码应为:(视频中不方便改,所以贴在这里)

void kernel_itoa(char buf, int num, int base) {
// 转换字符索引[-15, -14, …-1, 0, 1, …., 14, 15]
static const char
num2ch = {“FEDCBA9876543210123456789ABCDEF”};
char * p = buf;
int old_num = num;

  1. // 仅支持部分进制<br /> if ((base != 2) && (base != 8) && (base != 10) && (base != 16)) {<br /> *p = '\0';<br /> return;<br /> }
  2. // 只支持十进制负数 <br /> int signed_num = 0;<br /> if ((num < 0) && (base == 10)) {<br /> *p++ = '-';<br /> signed_num = 1;<br /> }

// 以下要对正负进行分开处理。对于十六进制数,不支持负数,所以需要将其转换成无符号数进行除和求余。原有的代码是按负数进行除和求余,导致转换结果不对。
if (signed_num) {
do {
char ch = num2ch[num % base + 15];
p++ = ch;
num /= base;
} while (num);
} else {
uint32_t u_num = (uint32_t)num;
do {
char ch = num2ch[u_num % base + 15];
p++ = ch;
u_num /= base;
} while (u_num);
}
*p— = ‘\0’;

  1. // 将转换结果逆序,生成最终的结果<br /> char * start = (!signed_num) ? buf : buf + 1;<br /> while (start < p) {<br /> char ch = *start;<br /> *start = *p;<br /> *p-- = ch;<br /> start++;<br /> }<br />}

参考资料