结构很奇怪 - C ++

时间:2012-02-17 04:32:57

标签: c++ struct

我对这个愚蠢的结构有很多麻烦。我不明白为什么会这样做,我真的不确定如何解决它。我知道如何修复它的唯一方法是删除结构并以其他方式执行(我不想这样做)。

所以我正在读取文件中的数据,而我正在将它读入一个结构指针。看起来我的'long long'的偏移/指针每次都搞砸了。查看下面的详细信息。

所以这是我的结构:

struct Entry
    {
        unsigned short type;
        unsigned long long identifier;
        unsigned int offset_specifier, length;
    };

这是我的代码,用于读取结构指针/数组中的所有废话:

Entry *entries = new Entry[SOME_DYNAMIC_AMOUNT];
fread(entries, sizeof(Entry), SOME_DYNAMIC_AMOUNT, openedFile);

如您所见,我将所有内容写入结构数组中。现在,我将向您展示我正在阅读的数据(对于此示例中的第一个结构)。

The bytes I am reading.

所以这是进入'entries'中第一个元素的数据。第一项(短,'类型')似乎很好。之后,当读取'标识符'时,似乎整个结构被移位了X个字节。这是第一个元素的图片(在反转结尾之后):

enter image description here

这是内存中的数据(红色方块是它开始的地方):

enter image description here

我知道这有点令人困惑,但我尽可能地解释它。感谢任何帮助,Hetelek。 :)

2 个答案:

答案 0 :(得分:6)

使用额外的字节填充结构,以便更快地访问字段。您可以使用#pragma pack阻止此操作:

#pragma pack(push, 1)

struct Entry
{
    /* ... */
};

#pragma pack(pop)

请注意,这可能不是100%可移植的(我知道至少GCC和MSVC支持x86)。

答案 1 :(得分:3)

以二进制形式读取和写入结构文件是危险的。

您遇到的问题是编译器在结构的typeidentifier成员之间插入填充(对齐所需)。显然,无论编写的程序,数据(你还没有告诉我们)都使用了一个不同的布局,即试图读取数据的程序。

如果两个系统(写入数据的系统和读取数据的系统)具有不同的对齐要求,因此Entry类型的布局不同,就会发生这种情况。

但是,协调不是唯一的潜在问题; endianness中的差异也可能是一个严重的问题。对于预定义的整数类型,不同的系统可能具有不同的大小。您不能假设struct Entry将具有一致的布局,除非处理它的所有代码都在单个系统上运行 - 并且理想情况下使用相同编译器的相同版本。

可能能够使用#pragma pack来解决这个问题,但我不建议这样做。它不可移植,it can be unsafe。充其量,它将解决成员之间填充的问题;从一个系统到另一个系统,布局仍然有很多种不同的方式。

如果不知道您正在阅读的文件的数据布局在何处以及如何定义,则无法为您提供明确的解决方案。

如果我们假设每条记录的文件布局是,例如:

  • 网络字节顺序(type
  • 中的2字节无符号整数
  • 网络字节顺序(identifier
  • 中的8字节整数
  • 网络字节顺序(offset_specifier, length
  • 中的4字节整数
  • 之间没有填充

然后你应该将数据读入unsigned char[]缓冲区,或者读入uint16_tuint32_tuint64_t类型的对象(在<cstdint>中定义)或<stdint.h>),然后将其从网络字节顺序转换为本地字节顺序。

您可以将此转换包装在从文件读取并转换数据的函数中,并将其存储在Entry结构中。

如果您可以假设程序只能在一组受限制的系统上运行,那么您可以绕过其中的一部分。例如,您可以调整struct Entry的声明,使其与文件格式匹配,并直接读取和写入。这样做意味着您的代码无法移植到某些系统。您必须决定愿意支付哪个价格。