fscanf读取Valgrind内存追踪文件时丢失地址前导7的问题
Valgrind内存追踪文件解析问题:前导7丢失的原因与解决
问题现象
读取Valgrind生成的内存追踪文件时,以7开头的内存地址(如7ff000398)被解析后丢失前导7,变成ff000398,导致内存地址识别错误,影响后续分区处理。
重现案例
测试文件内容
S 7ff000398,8 S 7ff000390,8
代码输出
Parsed line: # 0. Operation: S, address: ff000398, size: 8 Parsed line: # 1. Operation: S, address: ff000390, size: 8
问题代码
// some logic before this FILE * pFile; pFile = fopen(tracefile, "r"); if (!pFile) { fprintf(stderr, "unable to open %s\n", tracefile); exit(EXIT_FAILURE); } char operation_id; unsigned address; int size; // Line is of format " M 0x3242,4" or "I 0x324234,4" const char *format = " %c %16x,%d"; int i = 0; while (fscanf(pFile, format, &operation_id, &address, &size) > 0) { printf("Parsed line: # %d. Operation: %c, address: %16x, size: %d\n", i, operation_id, address, size); i++; }
原因分析
核心问题是类型宽度不匹配导致的数值截断:
%x格式符用于解析无符号十六进制整数,对应存储类型是unsigned int。在32位系统中,unsigned int仅占4字节(32位),最多能存储8位十六进制数(0~FFFFFFFF)。- 要解析的
7ff000398是9位十六进制数,对应36位二进制值,远超32位unsigned int的存储范围。fscanf会将超出范围的高位截断,只保留低32位,也就是ff000398,这就导致前导的7丢失了。 - 之前尝试添加
0x前缀无效,是因为前缀仅用于标识十六进制数,但类型宽度不足的核心问题未解决。
解决方案
修改代码中地址的存储类型和对应格式符,适配64位地址:
- 将
address的类型从unsigned改为unsigned long(或更明确的uint64_t,需包含<stdint.h>头文件)。 - 解析和输出时的格式符从
%x改为%lx(对应unsigned long),若使用uint64_t则用%lx或%llx(取决于编译器)。
修改后的代码示例:
// some logic before this #include <stdint.h> // 使用uint64_t需包含此头文件 FILE * pFile; pFile = fopen(tracefile, "r"); if (!pFile) { fprintf(stderr, "unable to open %s\n", tracefile); exit(EXIT_FAILURE); } char operation_id; uint64_t address; // 改用64位无符号整数存储地址 int size; const char *format = " %c %16lx,%d"; // 格式符改为%lx适配64位整数 int i = 0; while (fscanf(pFile, format, &operation_id, &address, &size) > 0) { printf("Parsed line: # %d. Operation: %c, address: %16lx, size: %d\n", i, operation_id, address, size); i++; }
这样就能完整解析9位甚至更长的十六进制内存地址,不会再出现截断丢失前导位的问题。
内容的提问来源于stack exchange,提问作者Deni
相关产品推荐
相关产品推荐

