关于8051内核单片机printf函数打印出错的一次记录

3242 分钟阅读
嵌入式开发

前言

在使用keil编译一款内核是8051的单片机后,发现printf函数与预期打印不符合,具体如下:

printf("buff_length: 0x%02x", 0x20);

输出:buff_length: 0x2001

原因

在标准 C 语言中,传入 printf 的常量(如 0x20)会发生“整型提升”。但在 Keil C51 编译器环境下,其底层的 printf 库在处理变长参数时,默认会按照 16 位(int)的大小去栈中读取数据。当你直接传入一个 8 位的十六进制常量时,C51 的参数压栈和运行时库的对齐方式可能会出现偏差,导致 printf 不仅读取了你传入的 0x20,还顺带把栈上相邻的下一个字节(在这里恰好是 0x01,可能来自于格式字符串的某些内部标记或栈上的残留数据)一起读走了,最终合并成了 0x2001 并打印出来。

解决方案

强制类型转换

显式地将传入的 8 位数据强制转换为 16 位的 unsigned int 类型即可。这样能确保该参数以完整的 16 位形式传递,避免 printf 在解析时发生栈错位。

// 显式转换为 unsigned int,确保占满16位,防止栈读取错位
printf("buff_length: 0x%02x", (unsigned int)0x20); 

使用 C51 特有的长度修饰符 b

// 明确告诉 printf 这是一个 8 位(char/byte)的数据
printf("buff_length: 0x%02bx", 0x20);