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

Python read与C语言fread读取同一二进制文件数据显示不一致原因

同JPG文件Python/C二进制读取结果不一致问题

问题现象

分别使用Python、C语言以二进制只读(rb)模式打开同一份39KB大小的JPG文件读取内容:

  1. Python侧读取得到文件长度为39038字节,输出的起始二进制序列为\xff\xd8\xff\xe0,参考代码如下:
aaa = open('C:\simfile\\testphoto.jpg','rb')
a = aaa.read()
print(len(a))  # 输出39038
print(a)
  1. C语言侧使用fread读取同一份文件后打印十六进制内容,输出结果和Python侧存在明显差异,参考代码如下:
#include <stdio.h>
#include <string.h>
#include<iostream>
#include <io.h>
#include<fcntl.h>
using namespace std;

int main()
{
   FILE *fp;
   fp = fopen("D:\\CbProject\\testphoto2.jpg", "rb");
   fseek(fp, 0, SEEK_SET);
   int mysize = 39038+1;
   rewind(fp);
   char buffer[mysize];
   fread(buffer, mysize, 1, fp);

   for(int i = 0;i<mysize;i++)
   {
        printf("%2x  ", buffer[i] );
   }

   fclose(fp);
   return(0);
}

问题根因

两边实际读取到的文件原始字节完全一致,输出差异是C代码存在写法缺陷导致的,具体问题点:

  • 核心问题是有符号char的符号扩展导致打印错误:x86平台下绝大多数C编译器默认将char类型定义为有符号类型(等价于signed char),取值范围为-128~127。当读取到的字节值≥0x80(十进制128)时,存入char变量会被识别为负数;调用printf通过%x输出时,char类型会先自动提升为int类型,负数提升时会将高位全部填充1做符号扩展,例如原始字节0xff存入signed char为-1,提升为32位int后值为0xffffffff,最终打印出8位f,和Python输出的单字节ff完全不符。
  • 存在越界读取无效值的问题:硬编码的读取长度mysize = 39038+1比文件实际长度多1字节,fread最多仅会读取文件内真实存在的39038字节,数组最后1位是栈上未初始化的随机内存值,打印出的这1字节本身就是无效垃圾数据。
  • 格式化输出符使用不当:%2x仅保证输出宽度为2、右对齐,遇到值小于0x10的字节(如0x01、0x0a)时不会补前导0,输出为单个数字,和Python侧的两位十六进制展示格式不一致。
  • 额外冗余:代码中先后调用fseek(fp, 0, SEEK_SET)和rewind(fp)都是将文件指针移到开头,属于重复操作,不影响结果但无必要。

修复方案

将存储字节的数组改为unsigned char类型避免符号扩展,动态获取文件真实长度替代硬编码,同时修正格式化输出符,修复后代码如下:

#include <stdio.h>

int main()
{
    FILE *fp = fopen("D:\\CbProject\\testphoto2.jpg", "rb");
    if (!fp) {
        perror("打开文件失败");
        return 1;
    }
    // 动态获取文件真实长度
    fseek(fp, 0, SEEK_END);
    int file_size = ftell(fp);
    rewind(fp);

    // 用无符号字符类型存储字节,从根源避免符号扩展问题
    unsigned char buffer[file_size];
    // 正确传参fread:单元素大小1字节,共读取file_size个元素
    size_t read_num = fread(buffer, 1, file_size, fp);
    if (read_num != file_size) {
        perror("读取文件失败");
        fclose(fp);
        return 1;
    }

    for(int i = 0; i < file_size; i++)
    {
        // 用%02x固定输出两位十六进制,不足补前导0
        printf("%02x  ", buffer[i]);
    }

    fclose(fp);
    return 0;
}

修复后重新运行,C侧打印的十六进制内容会和Python侧输出完全一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.30 12:12:22