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

C++读取二进制文件出现乱码:求原因分析与解决方案

二进制文件读取乱码问题分析与解决

问题背景

生成二进制文件的代码

#include <fstream>
int main() {
    unsigned char buf[] = {
        0x06, 0x00, 0x00, 0x00, 0x62, 0x6f, 0x79, 0x31, 0x00, 0x00, 0x00, 0x00,
        0x6d, 0x0f, 0x00, 0x00, 0xc8, 0x42, 0x9a, 0x99, 0xd9, 0x3f, 0x62, 0x6f,
        0x79, 0x32, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x10, 0x00, 0x00, 0xa0, 0x42,
        0x9a, 0x99, 0xd9, 0x3f, 0x62, 0x6f, 0x79, 0x33, 0x00, 0x00, 0x00, 0x00,
        0x6d, 0x11, 0x00, 0x00, 0x70, 0x42, 0x9a, 0x99, 0xd9, 0x3f, 0x62, 0x6f,
        0x79, 0x34, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x12, 0x00, 0x00, 0x20, 0x42,
        0x9a, 0x99, 0xd9, 0x3f, 0x67, 0x69, 0x72, 0x6c, 0x31, 0x00, 0x00, 0x00,
        0x66, 0x13, 0x00, 0x00, 0x48, 0x42, 0x9a, 0x99, 0xd9, 0x3f, 0x67, 0x69,
        0x72, 0x6c, 0x32, 0x00, 0x00, 0x00, 0x66, 0x13, 0x00, 0x00, 0x48, 0x42,
        0x9a, 0x99, 0xd9, 0x3f};
    std::ofstream fout("input", std::ofstream::binary);
    fout.write((char *)buf, sizeof(buf));
    fout.close();
    return 0;
}

文件结构

首字节0x06表示记录总数,后续每条记录包含:

  • name:8字节
  • gender:1字节('m'或'f')
  • age:4字节
  • weight:4字节(float)
  • height:4字节(float)

定义的读取结构体

struct Person{
    unsigned char name[8];
    unsigned char gender;
    unsigned int age;
    float weight,height;
}person[100];

读取代码

using namespace std;
ifstream fin;
fin.open("input",ios::binary);

int n;
fin.read(reinterpret_cast<char*>(&n),sizeof(n));

for(int i=0;i<n;i++)
     fin.read(reinterpret_cast<char*>(&person[i]),sizeof(person[i]));

输出乱码情况

输出代码:

for(int i=0;i<n;i++)
     cout<<person[i].name<<' '<<person[i].gender<<' '<<person[i].age<<' '<<person[i].weight<<' '<<person[i].height<<endl;

输出结果:

boy1  2577023688 7.00208e+28 1.81062e-41
 � 863596386 0 6.25119e-42
pB���?boy4  309133312 40 1.7
girl1  2577023560 1.74727e+25 4.63068e-39
 � 0 0 0
  0 0 0

问题原因

1. 记录数读取方式错误

文件首字节是单字节的记录数(0x06),但代码中用int n读取了4字节,会把后续3个0x00也读入n。虽然小端系统下n的值碰巧是6,但这一步已经消耗了4字节(正确应该只消耗1字节),导致后续所有记录的读取位置直接偏移了3字节,数据完全错位。

2. 结构体内存对齐导致字节偏移

C++编译器会自动对结构体成员进行内存对齐以提升访问效率:

  • name[8]占8字节(已满足对齐要求)
  • gender占1字节,为了让后面的age(4字节)对齐到4字节边界,编译器会在gender后填充3个空字节
    最终sizeof(Person)为24字节,但文件中每条记录实际只有21字节(8+1+4+4+4),每次读取24字节会跨记录读取,进一步加剧数据混乱。

解决方案

1. 修正记录数读取逻辑

改用单字节类型读取记录数,避免多读取字节:

unsigned char count;
fin.read(reinterpret_cast<char*>(&count), sizeof(count));
int n = static_cast<int>(count);

2. 取消结构体内存对齐

通过编译器指令强制结构体按1字节对齐,消除填充字节:

// 兼容MSVC、GCC、Clang的写法
#pragma pack(push, 1)
struct Person{
    unsigned char name[8];
    unsigned char gender;
    unsigned int age;
    float weight,height;
} __attribute__((packed)) person[100];
#pragma pack(pop)

3. 手动逐个读取成员(更安全)

如果不想依赖编译器指令,可逐个读取结构体成员,完全规避对齐问题:

for(int i=0;i<n;i++){
    fin.read(reinterpret_cast<char*>(person[i].name), sizeof(person[i].name));
    fin.read(reinterpret_cast<char*>(&person[i].gender), sizeof(person[i].gender));
    fin.read(reinterpret_cast<char*>(&person[i].age), sizeof(person[i].age));
    fin.read(reinterpret_cast<char*>(&person[i].weight), sizeof(person[i].weight));
    fin.read(reinterpret_cast<char*>(&person[i].height), sizeof(person[i].height));
}

4. 验证结果

修正后,输出会显示正确的内容,例如:

boy1 m 15 70.5 1.7
boy2 m 16 68 1.7
boy3 m 17 65 1.7
boy4 m 18 60 1.7
girl1 f 19 62 1.74
girl2 f 19 62 1.74

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 03:24:55