问题描述
在 ../sys/measure.c 第 260 行通过 dbg_info 打印调试信息:
dbg_info("nv=%d,p=%d,t=%d", temp_data.sensor_data[1].normal_volt, pos, tail);
现象
| 查看方式 | nv | pos | tail |
|---|---|---|---|
| Debug 观察窗(读内存) | ✅ 正确 | ✅ 正确 | ✅ 正确 |
| printf 打印输出 | ✅ 正确 | ❌ 始终为 0 | ✅ 正确 |
核心矛盾:变量在内存中的值都是对的,但 printf 打印出来 pos 却是 0。
根因分析
2.1 变量类型
typedef struct {long long normal_volt; // 8 字节(64位)...} sensor_data_t;int pos; // 4 字节(32位)int tail; // 4 字节(32位)
2.2 Debug 观察窗 vs printf 的读取机制
| 方式 | 如何读取变量值 | 受格式符影响? |
|---|---|---|
| Debug 观察窗 | 通过符号表找到变量内存地址,直接按类型读取 | ❌ 不经过 varargs |
| printf | 从 varargs 栈上按格式符指定的长度逐字节消费 | ✅ 全靠格式符 |
Debug 观察窗完全绕过了 printf 的变参机制,所以三个值都正确——这恰好证明了变量本身的值没有问题。
2.3 printf 参数错位过程
printf("nv=%d,p=%d,t=%d", normal_volt, pos, tail)
调用时,三个参数依次压入 varargs 栈,printf 按 %d(4 字节)逐个消费:
栈布局 (低地址在上,printf 从低地址向高地址依次取 %d):┌──────────────────────┐│ normal_volt 低4字节 │ ← %d#1→ 打印 "nv" (正确)├──────────────────────┤│ normal_volt 高4字节 │ ← %d#2→ 打印 "pos" (恒为 0)├──────────────────────┤│ pos (4字节) │ ← %d#3→ 打印 "tail" (实际是 pos 的值)├──────────────────────┤│ tail (4字节) │ 未读取└──────────────────────┘
| 格式符 | 读到什么 | 打印显示 |
|---|---|---|
%d#1 |
normal_volt 低 32 位 |
nv = 正确值(数值小,仅占用低 32 位) |
%d#2 |
normal_volt 高 32 位 |
pos = 0(高位恒为 0) |
%d#3 |
真正的 pos 值 |
tail = 正确值(实际是 pos 的值,碰巧相近) |
2.4 为什么 nv 和 tail "看起来"正确
nv 正确:normal_volt 数值较小(低 32 位就够表示),高 32 位为 0,低 32 位被 %d#1 读取后自然正确;tail 正确:%d#3 实际读到的是 pos 的真实值,在测试场景下 pos 和 tail 的数值恰好相近或相等,造成"tail 也对"的假象;
实际上三个变量全部错位,只是两个碰巧对上了。
3. 解决方案
// 错误:%d 只能读 4 字节,long long 是 8 字节
dbg_info("nv=%d,p=%d,t=%d", temp_data.sensor_data[1].normal_volt, pos, tail);
// 正确:%lld 读 8 字节,后续参数自动对齐
dbg_info("nv=%lld,p=%d,t=%d", temp_data.sensor_data[1].normal_volt, pos, tail);
4. 经验总结
| 要点 | 说明 |
|---|---|
| Debug 观察窗正确 ≠ printf 正确 | Debug 窗口读内存地址,printf 走 varargs,两者路径完全不同 |
| 部分正确不代表整体正确 | 即使某些变量值看起来对,也可能是"碰巧",不代表参数对齐正确 |
| 格式符必须严格匹配类型 | 字节数不对 → 所有后续参数全错位 |
| 启用编译警告 | 开启 -Wformat 可让编译器自动检测此类问题 |
5. 常见类型格式符速查
| C 类型 | sizeof | 格式符 |
|---|---|---|
int |
4 | %d |
unsigned int |
4 | %u |
short |
2 | %hd |
long |
4/8 | %ld |
long long |
8 | %lld |
float |
4 | %f |
double |
8 | %f 或 %lf |
char * |
4/8 | %s |
void * |
4/8 | %p |
阅读全文
43