对象序列化有一个奇怪的问题。
在文件文档中它指出如下
导入以4字节标签开头
标识TDMS段
(“ TDSm”)。接下来的四个字节被使用
作为位掩码以指示
该细分是什么样的数据
包含。此位掩码称为
作为目录(目录)。任何
以下标志的组合可以
在ToC中编码:接下来的四个
字节包含版本号(32位
无符号整数),它指定
最早的TDMS修订版
符合。在这个时候
写作,版本号是4713。
TDMS的唯一先前版本具有
数字4712。接下来的八个字节
(64位无符号整数)描述
剩余段的长度
(段的总长度减去
引线的长度)。如果进一步
段添加到文件中,
该号码可用于查找
以下的起点
分割。如果遇到应用程序
写入一个严重的问题
TDMS文件(崩溃,断电),全部
该整数的字节可以为0xFF。
这只能发生到最后
文件中的段。最后八
字节(64位无符号整数)
描述整个的长度
细分中的元信息。这个
信息用于随机访问
原始数据。如果段
根本不包含任何元数据
(属性,索引信息,对象
list),则该值为0。
所以我实现为
class TDMsLEADIN {
public:
char Signature[4]; //TDSm
__int32 Toc;
unsigned __int32 vernum;
unsigned __int64 nextSegmentOff;
unsigned __int64 rawDataOff;
};
fread(&leadin,sizeof(TDMsLEADIN),1,f);
然后我得到了签名=“ TDsm”,TOc = 6,vernum = 4712。
nextSegmentOff = 833223655424,rawDataOff = 8589934592,但同时预期nextSegmentOff和rawDataOff = 194
然后我将课程分为两部分,并分别阅读了两部分
class TDMsLEADIN {
public:
char Signature[4]; //TDSm
__int32 Toc;
unsigned __int32 vernum;
};
class TDMsLeadINend{
public:
unsigned __int64 nextSegmentOff;
unsigned __int64 rawDataOff;
};
fread(&leadin,sizeof(TDMsLEADIN),1,f);
fread(&leadin2,sizeof(TDMsLeadINend),1,f);
然后我得到了nextSegmentOff,rawDataOff按预期= 194。
我的问题是原始代码有什么问题?将其分为两部分时为什么会起作用?我尝试了很长一段时间的unsigned而不是unsigned __int64,但是结果仍然相同。
这很奇怪。
谢谢
最佳答案
您似乎只是直接在结构中读写二进制数据。
通常,编译器将对齐结构数据以提高性能,因此当它是单个结构时,在vernum
和nextSegmentOff
之间会有一个隐藏的32位填充以对齐nextSegmentOff
。当它分成两个结构时,就没有这种额外的填充,并且您正在将四个字节的填充和四个字节的实际数据读入nextSegmentOff
中。
您可以通过将sizeof(TDMsLEADIN [second version]) + sizeof(TDMsLeadINend)
与sizeof(TDMsLEADIN [first version])
进行比较来进行测试
序列化数据的标准方法是分别序列化每个基础块,而不是依赖类或结构的布局,因为类或结构的布局可以由编译器更改而无需通知。