不使用stdarg.h实现C语言简易printf函数的错误修复
修复手动实现可变参数printf的问题
核心错误分析
你的代码读取可变参数时出现垃圾值,根源有两个:
- 指针步长错误:用
void**遍历参数时,每次arg++会跳过一个指针大小(64位系统下是8字节),但int类型仅占4字节,导致读取位置偏移,拿到的是栈上的垃圾数据。 - 整数溢出未处理:
print_int中当输入为INT_MIN(int类型的最小值)时,n = -n会触发溢出,属于未定义行为。
修复后的完整代码
#include <stdio.h> #include <limits.h> // 用于INT_MIN定义 void print_uint(unsigned int n) { if (n / 10) print_uint(n / 10); putchar(n % 10 + '0'); } void print_int(int n) { if (n < 0) { putchar('-'); // 转换为unsigned int处理INT_MIN,避免溢出 print_uint((unsigned int)-n); return; } print_uint((unsigned int)n); } void print_string(char *s) { while (*s) putchar(*s++); } void my_printf(char *format, ...) { // 用char*跟踪参数位置,初始指向format参数后的第一个可变参数 char *arg = (char*)&format + sizeof(format); for (char *p = format; *p; p++) { if (*p != '%') { putchar(*p); continue; } switch (*++p) { case 'd': { int val = *(int*)arg; print_int(val); arg += sizeof(int); break; } case 'u': { unsigned int val = *(unsigned int*)arg; print_uint(val); arg += sizeof(unsigned int); break; } case 's': { char *val = *(char**)arg; print_string(val); arg += sizeof(char*); break; } case '%': putchar('%'); break; default: putchar(*p); break; } } } int main() { int x = 42; unsigned int y = 1234567890; char *s = "Hello, world!"; int min_int = INT_MIN; // 测试INT_MIN情况 my_printf("Testing my_printf:\n"); my_printf("Signed integer: %d\n", x); my_printf("Unsigned integer: %u\n", y); my_printf("String: %s\n", s); my_printf("Percent sign: %%\n"); my_printf("INT_MIN: %d\n", min_int); // 新增测试 return 0; }
关键修复点说明
- 参数指针调整:改用
char*作为参数跟踪指针,每次根据当前参数的实际大小(sizeof(int)/sizeof(unsigned int)/sizeof(char*))移动指针,确保读取位置正确。 - INT_MIN处理:将负数转换为
unsigned int后调用print_uint,避免直接取反导致的溢出问题。
测试输出
修复后运行会得到正确结果:
Testing my_printf: Signed integer: 42 Unsigned integer: 1234567890 String: Hello, world! Percent sign: % INT_MIN: -2147483648
内容的提问来源于stack exchange,提问作者Dremond Williams
相关产品推荐
相关产品推荐

