将文件读入结构时出现问题

时间:2012-07-18 09:09:46

标签: c++ struct binary

我已经定义了这个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);

结构有什么问题?为什么我会得到不同的结果?

7 个答案:

答案 0 :(得分:1)

几乎可以肯定,你的struct中有 padding 。编译器在estindefmax和maxiedisc成员之间放置了两个额外的字节。这就是为什么直接读取结构是一个坏主意,除非你用完全相同的结构编写文件。

没有结构,你是第二种方式。如果这是您需要的,请稍后填写结构。

答案 1 :(得分:1)

直接从内存到磁盘读取和写入文件是不可移植的。

您可能遇到的一些问题是

  • 内存填充。 (编译器依赖)您可以使用#pragma pack(vs)来避免这种情况,但CPu将以更低效的方式使用这些结构。
  • 尾段-ESS 即可。整数类型可以以Little-Ending或Big-Endian格式存储(取决于平台)。可以使用boost::endian函数族
  • 进行转换
  • 保存复杂的数据结构(STL列表,矢量等)
  • 结构版本化。在较新的程序中加载旧版本的结构。

正确的方法是使用已经封装所有这些问题的序列化库(例如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