我已经定义了这个struc来读取二进制文件
struct cabecera{
unsigned long time;
short lrec;
short eddimdat;
short edmaxdat;
short edncn;
short estindefmax;
long maxiedisc;
long edbuit;
long edusat;
short estindefusat;
long libdoff;
long vidoff;
long dgoff;
long estindefoff;
long estinoff;
long sedoff;
long esdoff;
int libvers;
long offie;
long tiueoff;
};
我有一个从fstream扩展到读取数据的类
open(fNombre.c_str(),ios::in|ios::binary);
if(fail()||bad()) return;
int pos = 160 ;
cabecera cb={};
seekg(pos,ios::beg);
read((char*)&cb, sizeof(cb));
但变量maxiedisc得到一个错误的值(1052835858),其余的变量来自这里 如果我在没有结构的情况下读取此变量,则我获得的值是正确的(1200000)
int tmLong = sizeof(long);
int tmULong = sizeof(unsigned long);
int tmShort = sizeof(short);
int pos = 160 + tmULong + (tmShort*5);
seekg(pos,ios::beg);
long maxiedisc;
read((char*)&maxiedisc, tmLong);
结构有什么问题?为什么我会得到不同的结果?
答案 0 :(得分:1)
几乎可以肯定,你的struct中有 padding 。编译器在estindefmax和maxiedisc成员之间放置了两个额外的字节。这就是为什么直接读取结构是一个坏主意,除非你用完全相同的结构编写文件。
没有结构,你是第二种方式。如果这是您需要的,请稍后填写结构。
答案 1 :(得分:1)
直接从内存到磁盘读取和写入文件是不可移植的。
您可能遇到的一些问题是
#pragma pack
(vs)来避免这种情况,但CPu将以更低效的方式使用这些结构。 boost::endian
函数族正确的方法是使用已经封装所有这些问题的序列化库(例如Boost::serialization
或google的ProtoBuff
),或者如果库的开销太大而无法编写一些序列化程序你自己。它听起来比听起来容易。只需编写两个成员函数(保存/加载),用于向/从流写入/读取成员。你应该自己处理endian-ess和版本控制。
答案 2 :(得分:0)
您需要禁用编译器的填充。它会为你的结构添加填充字节,使其比你想象的更大 由于您没有提到您使用的编译器:Here是如何在msvc上完成的。如果我记得grcc具有相同的语法。但是我没试过。
答案 3 :(得分:0)
看起来像填充问题
使用gcc try直接读入结构
struct my_struct {
/* ... */
} __attribute__((packed));
这确保了没有使用填充
答案 4 :(得分:0)
正如@john所提到的,问题似乎是结构填充。
你有两个解决方法来摆脱填充,第一个是逐个编写每个结构组件(但是这个大小的结构不是最好的方式)第二个是按照其他用户的建议禁用填充
#ifndef LINUX
#pragma pack(1)
#endif
struct cabecera
{
// your stuff...
}__attribute__((packed));
#else
};
#endif
PS:不要在你的代码上混合语言,它看起来很傻;)“ si programaseninglés,usaelinglésparanombrar variables y datos ”
答案 5 :(得分:0)
您可以使用类似Google protobuf的内容为您执行结构的序列化/反序列化。这种方法更安全,适用于编译器和系统边界。另一种方法是单独序列化每个字段。打包有时是最快的选择,但在编译器兼容性和系统之间的二进制兼容性方面存在问题。
答案 6 :(得分:0)
#pragma pack(push,1)
// struct definition
#pragma push