结构填充

时间:2011-04-27 13:02:11

标签: c++ struct padding

我正在尝试将文件中的数据块直接读取到结构中,但是填充会导致读取太多数据并且数据未对齐。

我是否必须手动将每个部分读入结构中,或者是否有更简单的方法来执行此操作?

我的代码:

结构

typedef unsigned char byte;

struct Header
{
    char ID[10];
    int  version;
};

struct Vertex //cannot rearrange the order of the members
{
    byte    flags;
    float   vertex[3];
    char    bone;
    byte    referenceCount;
};

我如何阅读数据:

std::ifstream in(path.c_str(), std::ifstream::in | std::ifstream::binary);

Header header;
in.read((char*)&header.ID, sizeof(header.ID));
header.ID[9] = '\0';
in.read((char*)&header.version, sizeof(header.version));
std::cout << header.ID << " " << header.version << "\n";
in.read((char*)&NumVertices, sizeof(NumVertices));
std::cout << NumVertices << "\n";

std::vector<Vertex> Vertices(NumVertices);

for(std::vector<Vertex>::iterator it = Vertices.begin(); it != Vertices.end(); ++it)
{
    Vertex& v = (*it);
    in.read((char*)&v.flags, sizeof(v.flags));
    in.read((char*)&v.vertex, sizeof(v.vertex));
    in.read((char*)&v.bone, sizeof(v.bone));
    in.read((char*)&v.referenceCount, sizeof(v.referenceCount));
}

我尝试过:in.read((char*)&Vertices[0], sizeof(Vertices[0]) * NumVertices);但由于我认为是填充,这会产生错误的结果。

另外:目前我正在使用C风格的强制转换,在这种情况下使用的C ++转换是正确的,还是C风格的转换?好的?

6 个答案:

答案 0 :(得分:3)

如果您以二进制形式编写整个结构,则无需像单独存储每个变量一样阅读它。您只需将文件中的结构大小读入您定义的结构中。

Header header;
in.read((char*)&header, sizeof(Header));

如果您总是在相同的架构或同一台机器上运行,则无需担心端序问题,因为您将以与应用程序读取它们相同的方式编写它们。如果您是在一个体系结构上创建文件并期望它在另一个体系结构上是可移植/可用的,那么您将需要相应地交换字节。我过去这样做的方法是创建一个我自己的交换方法。 (例如Swap.h)

Swap.h - This is the header you use within you're code

void swap(unsigned char *x, int size);

------------------

SwapIntel.cpp - This is what you would compile and link against when building for Intel

void swap(unsigned char *x, int size)
{
    return;   // Do nothing assuming this is the format the file was written for Intel (little-endian)
}

------------------

SwapSolaris.cpp -  This is what you would compile and link against when building for Solaris

void swap(unsigned char *x, int size)
{
    // Byte swapping code here to switch from little-endian to big-endian as the file was written on Intel
    // and this file will be the implementation used within the Solaris build of your product
    return;   
}

答案 1 :(得分:2)

不,您不必单独阅读每个字段。这称为对齐/包装。见http://en.wikipedia.org/wiki/Data_structure_alignment

C风格演员等同于reinterpret_cast。在这种情况下,您可以正确使用它。您可以使用特定于C ++的语法,但输入的内容要多得多。

答案 2 :(得分:2)

您可以通过明确要求编译器在1个字节而不是4个字节或其默认值上对齐结构来更改填充。根据环境的不同,这可以通过多种不同的方式完成,有时是逐个文件('编译单元'),甚至是逐个struct(带编译指示等)或仅在整个项目中。

答案 3 :(得分:2)

  

header.ID[10] = '\0';

header.ID [9]是数组的最后一个元素。

答案 4 :(得分:1)

如果您使用的是Microsoft编译器,请浏览align pragma。还有对齐包含文件:

#include <pshpack1.h>
// your code here
#include <poppack.h>

GNU gcc有一个不同的系统,允许你在结构定义中添加对齐/填充。

答案 5 :(得分:0)

如果您自己阅读和编写此文件,请尝试使用Google Protobuf库。它将处理所有字节顺序,对齐,填充和语言互操作问题。

http://code.google.com/p/protobuf/