C++读取二进制文件拆分位域赋值给struct成员结果异常求助
问题原因排查
你代码里的问题主要出在三个地方:
- 读取二进制文件用了
>>运算符:>>是专门用于文本格式读取的运算符,会自动跳过空白字符、按照文本规则解析内容,根本不适合读取二进制数据,导致你读进payload数组的内容根本不是文件里存储的二进制数值。 - 结构体字节对齐问题:默认编译器会对结构体成员做内存对齐优化,
uint8_t id之后会插入1字节的空白填充,保证后面的uint16_t x_data按2字节地址对齐,你直接把数组指针强转成结构体指针的话,拿到的x_data对应位置完全错位。 - uint8_t输出格式问题:直接用
cout打印uint8_t类型变量会被识别为字符类型,无法正常输出数字值。
修复方案
第一步:修改二进制读取逻辑
把file >> payload替换为read方法,明确指定要读取的字节数:
file.read(reinterpret_cast<char*>(payload), sizeof(sf_payload_t));
第二步:取消结构体字节对齐
给结构体加对齐属性,避免编译器插入填充字节,GCC/Clang环境下写法如下:
typedef struct __attribute__((packed)) st_payload_t{ uint8_t id; uint16_t x_data; }sf_payload_t;
如果是MSVC编译环境,需要在结构体定义前后加编译指令:
#pragma pack(1) typedef struct st_payload_t{ uint8_t id; uint16_t x_data; }sf_payload_t; #pragma pack()
补充说明:字节序适配
如果你的存储文件是按大端字节序(高字节在前)存储的,运行代码的CPU是小端架构(常见的x86/x86_64都是小端),非全0/全F的数值读取后需要做字节序转换,可以用ntohs函数把网络字节序(大端)转成本地字节序。
完整修正代码
#include <fstream> #include <iostream> #include <cstdint> // ntohs函数头文件,Windows下换为winsock2.h #include <arpa/inet.h> using namespace std; // GCC/Clang 无对齐属性结构体定义 typedef struct __attribute__((packed)) st_payload_t{ uint8_t id; uint16_t x_data; }sf_payload_t; int main() { ifstream file; file.open("s_file", ios::binary|ios::in); if(file.is_open()){ uint8_t payload[200]={0}; file.seekg(0, file.beg); // 按指定长度读取二进制内容 file.read(reinterpret_cast<char*>(payload), sizeof(sf_payload_t)); sf_payload_t* data_1 = reinterpret_cast<sf_payload_t*>(&payload[0]); // 大端转本地字节序,不需要可删除该行 data_1->x_data = ntohs(data_1->x_data); // 把uint8_t转成unsigned int保证按数字格式输出 std::cout << "data id: "<< static_cast<unsigned int>(data_1->id)<< std::endl; std::cout << "data x_data: "<< data_1->x_data<< std::endl; } else{ std::cout << "Not reading" << '\n'; } return 0; }
内容的提问来源于stack exchange,提问作者Sergio Prieto
相关产品推荐
相关产品推荐

