You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C语言读取二进制文件做十六进制转储时输出带ffffff前缀原因

Game Boy存档二进制读取异常问题

问题背景

近期在尝试进行Game Boy存档修改,正在学习C语言环境下的二进制文件读取方法。已知char类型长度为1字节,因此编写如下代码读取文件字节内容:

#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main () {
   FILE *fp = NULL;
   char buffer[100];
   int filesize;

   fp = fopen("save file.srm", "r+"); // 打开存档文件
   if(fp == NULL) printf("File loading error number %i\n", errno); 
   fseek(fp, 0L, SEEK_END); // 指针移动到文件末尾获取文件大小
   filesize = ftell(fp);
   printf("Filesize is %i bytes\n",filesize);
   
   fseek(fp, 0, SEEK_SET); // 将读指针重置到文件开头
   fread(buffer, sizeof buffer, 1, fp); // 读取内容到缓冲区
   
   for(int i=70;i<80;i++) printf("%x\n", buffer[i]); // 打印指定区间字节
   
   fclose(fp);
   
   return(0);
}

实际运行输出

Filesize is 32768 bytes
ffffff89
66
ffffff85
2
2
ffffff8b
44
ffffff83
c
0

问题描述

预期读取到的单字节数值最大为0xff,即每行输出两位十六进制数,但实际输出中出现了ffffff89、ffffff8b这类超出单字节范围的数值,需要明确问题产生的具体原因。

问题根因

出现该现象是两个C语言规则共同作用的结果:

  • char类型的符号性由编译器实现决定:在绝大多数x86、x86_64架构的常见编译器配置下,char默认是有符号类型,取值范围为-128~127。当读取到的字节值大于等于0x80(十进制128)时,存入有符号char变量会被识别为负数。
  • 可变参数函数的整型提升规则:向printf这类支持可变参数的函数传入char类型值时,char会被自动提升为int类型。有符号类型的负值在做类型提升时会执行符号位扩展:例如字节值0x89存入有符号char后为-119,符号位扩展为32位int后值为0xffffff89,用%x按十六进制输出时就会显示前缀的多个f。

另外代码还存在一个隐藏问题:打开二进制文件使用了文本模式"r+",在Windows等平台下文本模式会自动对换行、特殊EOF字符做转义处理,可能导致读取到的字节和文件实际内容不一致。

修正方法

  • 将缓冲区类型从char改为unsigned char,明确使用无符号类型存储原始字节,从根源避免符号位扩展问题:unsigned char buffer[100];
  • 二进制文件打开时使用二进制读写模式,将fopen的模式参数从"r+"改为"rb+"
  • 如果需要固定输出两位十六进制数,可以将打印格式符从%x改为%02x,不足两位时自动前置补0。

内容的提问来源于stack exchange,提问作者Jojo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 20:57:22