0

我已经定义了这个结构来读取二进制文件

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);

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

4

7 回答 7

1

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

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

于 2012-07-18T09:15:58.993 回答
1

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

您可能遇到的一些问题是

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

正确的方法是使用已经封装了所有这些问题的序列化库(如Boost::serialization或 google 的ProtoBuff),或者如果库的开销太大而无法自己编写一个小序列化程序。这比听起来容易。只需编写两个成员函数(保存/加载),将成员写入流/从流中读取。您应该处理自己的字节序和版本控制。

于 2012-07-18T10:04:07.007 回答
0

正如@john 所提到的,问题似乎是结构填充。

您有两种解决方案来消除填充,第一个是逐个编写每个结构组件(但在这种大小的结构中不是最好的方法),第二个是按照其他用户的建议禁用填充。

#ifndef LINUX
#pragma pack(1)
#endif
struct cabecera
{
    // your stuff...
}__attribute__((packed));
#else
};
#endif

PS:不要在你的代码中混合语言,它看起来很傻;)“ si programas en inglés, usa el inglés para nombrar variables y datos

于 2012-07-18T09:22:33.687 回答
0

您需要禁用编译器的填充。它将向您的结构添加填充字节,使其比您预期的要大。
由于您没有提及您使用的编译器:是在 msvc 上完成的。如果我记得正确 gcc 具有相同的语法。但Inever试过了。

于 2012-07-18T09:18:25.217 回答
0

看起来像填充问题

使用 gcc 直接读入结构体

struct my_struct {
    /* ... */
} __attribute__((packed));

这确保不使用填充

于 2012-07-18T09:18:45.193 回答
0

您可以使用 Google protobuf之类的东西为您执行结构的序列化/反序列化。这种方法更安全,并且可以跨编译器和系统边界工作。另一种方法是单独序列化每个字段。打包有时是最快的选择,但在编译器兼容性和系统之间的二进制兼容性方面存在问题。

于 2012-07-18T09:44:36.690 回答
0
#pragma pack(push,1)
// struct definition
#pragma push
于 2012-07-18T09:50:49.360 回答