如何在xv6操作系统中打印long long类型整数?
在xv6中打印long long类型整数的解决方案
xv6自带的printf是极简实现,仅支持%d、%x、%s等基础格式符,没有对long long对应的ll修饰符做适配,所以直接用%llu/%lld会失效。以下是两种可行的解决办法:
方案一:手动实现long long转字符串函数
自己编写转换函数将long long/unsigned long long转为字符串,再通过printf("%s")打印。以下是可直接复用的实现:
无符号long long转字符串(ulltoa)
#include <stdint.h> void ulltoa(uint64_t num, char *buf, int base) { char *ptr = buf, *ptr1 = buf, tmp_char; uint64_t tmp_num; // 生成逆序的数字字符 do { tmp_num = num; num /= base; *ptr++ = "0123456789abcdef"[tmp_num - num * base]; } while (num != 0); // 添加字符串结束符 *ptr = '\0'; // 反转字符串得到正确顺序 while (ptr1 < --ptr) { tmp_char = *ptr1; *ptr1++ = *ptr; *ptr = tmp_char; } }
有符号long long转字符串(lltoa)
基于上面的ulltoa处理负数情况:
void lltoa(int64_t num, char *buf, int base) { char *ptr = buf; uint64_t unum; // 十进制负数添加负号 if (base == 10 && num < 0) { *ptr++ = '-'; unum = (uint64_t)-num; } else { unum = (uint64_t)num; } ulltoa(unum, ptr, base); }
使用示例
#include "types.h" #include "stdio.h" // 上面的ulltoa和lltoa函数放在此处 int main() { long long signed_num = -123456789012345LL; unsigned long long unsigned_num = 987654321098765ULL; char buf[64]; // 打印有符号long long lltoa(signed_num, buf, 10); printf("Signed long long: %s\n", buf); // 打印无符号long long ulltoa(unsigned_num, buf, 10); printf("Unsigned long long: %s\n", buf); // 十六进制打印 ulltoa(unsigned_num, buf, 16); printf("Hex unsigned long long: 0x%s\n", buf); return 0; }
方案二:修改xv6的printf源码,添加ll修饰符支持
直接修改xv6自带的printf.c,让原生printf支持%lld和%llu:
- 打开xv6源码目录下的
printf.c,修改printnum函数的参数类型为uint64_t(兼容unsigned long long):
static int printnum(uint64_t num, int base, int sign) { char buf[32]; char *ptr = buf + sizeof(buf); int len = 0; if(num == 0){ *--ptr = '0'; } else { while(num > 0){ *--ptr = "0123456789abcdef"[num % base]; num /= base; } } if(sign){ *--ptr = '-'; } while(ptr < buf + sizeof(buf)){ len += putchar(*ptr++); } return len; }
- 在
printf函数中添加ll修饰符的解析逻辑,并适配long long类型参数:
int printf(const char *fmt, ...) { va_list ap; int len = 0; uint64_t uv; int64_t v; char *s; va_start(ap, fmt); while(*fmt){ if(*fmt != '%'){ len += putchar(*fmt++); continue; } fmt++; // 解析ll修饰符 int is_longlong = 0; if(*fmt == 'l'){ fmt++; if(*fmt == 'l'){ is_longlong = 1; fmt++; } } switch(*fmt){ case 'd': if(is_longlong){ v = va_arg(ap, int64_t); if(v < 0){ len += putchar('-'); uv = -v; } else { uv = v; } } else { int iv = va_arg(ap, int); if(iv < 0){ len += putchar('-'); uv = -iv; } else { uv = iv; } } len += printnum(uv, 10, 0); break; case 'u': if(is_longlong){ uv = va_arg(ap, uint64_t); } else { uv = va_arg(ap, unsigned int); } len += printnum(uv, 10, 0); break; case 'x': if(is_longlong){ uv = va_arg(ap, uint64_t); } else { uv = va_arg(ap, unsigned int); } len += printnum(uv, 16, 0); break; case 's': s = va_arg(ap, char*); while(*s){ len += putchar(*s++); } break; case 'c': len += putchar(va_arg(ap, int)); break; case '%': len += putchar('%'); break; default: len += putchar('%'); len += putchar(*fmt); break; } fmt++; } va_end(ap); return len; }
- 修改完成后重新编译xv6:
make clean && make
- 之后即可直接使用
%lld和%llu打印long long类型:
long long test_signed = -987654321012345LL; unsigned long long test_unsigned = 123456789012345ULL; printf("Signed: %lld\nUnsigned: %llu\nHex: %llx\n", test_signed, test_unsigned, test_unsigned);
内容的提问来源于stack exchange,提问作者YH J
相关产品推荐
相关产品推荐

