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

C++自定义BinaryReader读取TTF文件时数值读取结果异常问题

问题根因

你遇到的问题由两个原因共同导致:

  • 核心原因是字节序(端序)不匹配:TTF格式规范规定所有多字节整数字段均采用大端序(Big-Endian,高位字节存储在低偏移位置),而x86、x86_64等绝大多数消费级CPU采用小端序(Little-Endian,低位字节存储在低地址)。你直接将文件二进制内容读取到uint16_t/uint32_t类型变量的内存空间中,没有做端序转换,得到的数值自然是错误的。
    你提到的scalar type字段期望值为65536,对应十六进制值为0x00010000,在TTF文件中存储的字节顺序为00 01 00 00。小端序CPU直接读取这4字节解析为uint32_t时,会将第一个字节作为数值最低位,最终解析出0x00000100即256,和你实际输出的结果完全吻合。
  • 你将fi.read的读取长度改为3621这类随机值仍输出256,是因为该操作属于典型的栈缓冲区溢出未定义行为:uint32_t类型变量x仅占4字节内存,你要求read写入3621字节,会直接覆盖x变量地址后方的栈内存(包括其他局部变量、函数返回地址等),但x本身所在的4字节内存恰好被写入了和读取4字节时完全相同的内容,因此返回值没有变化。这种操作轻则导致程序随机崩溃、输出乱码,重则可被利用执行恶意代码,绝对不要在实际代码中使用。
修复方案

不要直接将多字节内容整块读取到整型变量内存中,改为逐字节读取后按大端序手动拼接数值,该写法不依赖运行环境的CPU端序,也不会出现内存对齐、越界问题。
修复后的多字节读取方法实现如下:

// 原getUInt8实现无需修改
int getUInt8(){
    fi.seekg(position, ios::beg);
    uint8_t x;
    fi.read((char*)&x, sizeof(x));
    position+=sizeof(x);
    return (int)x;
}

int getUInt16(){
    uint16_t res = 0;
    // 大端序第一个字节是高位,左移8位
    res |= (uint16_t)getUInt8() << 8;
    res |= (uint16_t)getUInt8();
    return (int)res;
}

int getUInt32(){
    uint32_t res = 0;
    // 大端序按从高到低顺序拼接每个字节
    res |= (uint32_t)getUInt8() << 24;
    res |= (uint32_t)getUInt8() << 16;
    res |= (uint32_t)getUInt8() << 8;
    res |= (uint32_t)getUInt8();
    return (int)res;
}

替换原有实现后,读取到的scalar type、numTables等字段值就会和TTF规范定义的预期值一致。


内容的提问来源于stack exchange,提问作者Luna Le Tuna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 21:57:22