无需reinterpret_cast即可读取二进制数据

时间:2010-03-01 14:57:56

标签: c++ casting binary

因为我在编写读取二进制STL文件的程序之前从未读过二进制文件。我使用ifstream读取成员来获取char *参数。要将我的结构转换为char *,我使用reinterpret_cast。但据我记得每本关于C ++的书我读到的都说“不要使用reinterpret_cast,除非你必须”。什么是更好的方式读取二进制数据,不一定是直接的,但最后是一个结构,没有reinterpret_cast?

主要功能:

std::ifstream in (cmdline[1].c_str(), std::ios::binary);

in.seekg(80, std::ifstream::beg); //skip header

int numTriangle;
in.read (reinterpret_cast<char*>(&numTriangle), sizeof(int)); //determine number of triangles
//create triangle data type and read data
triangle* t = new triangle();
for (int i = 0; i < numTriangle; ++i)  {
    in.read(reinterpret_cast<char*>(t), triangle::size);
    std::cout << *t;  // there's an opertor<< for triangle
}
delete t;

in.close(); //close file read from

三角形结构

//attempt to get the right size of a class without structure padding
#pragma pack(push)
#pragma pack(1)

//standard STL triangle data structure
struct triangle {
public:
    float n[3]; //normals, 4*3=12 bytes

    float x[3]; //first point of the triangle, 4*3=12 bytes
    float y[3]; //second point of the triangle, 4*3=12 bytes
    float z[3]; //third point of the triangle, 4*3=12 bytes

    long int a; //attributes, 2 bytes

    static const int size = 12+12+12+12+2; //sum of member variables
    //static const int size = sizeof(n) + sizeof(x) + sizeof(y) + sizeof(z) + sizeof(a);
};
#pragma pack(pop)

(额外的问题:#pragma pack(1)不适用于cygwins g ++ - 4.如何确定结构的大小?)

3 个答案:

答案 0 :(得分:6)

嗯,那段代码看起来不错。你甚至关心填充问题。我看不出你怎么能避免在这里施展。你可以这样做:

static_cast<char*>(static_cast<void*>(t))

但实际上,我不会在我的代码中这样做。对char*做直接reinterpret_cast只是一种吵闹的方式。 (见casting via void* instead of using reinterpret_cast)。


可以使用sizeof确定结构大小。您只需要在static内的类中初始化.cpp成员(但是,编译器不再知道::size的值,并且不能内联它)。
或者,您可以将其编写为静态内联成员函数。在其正文中,类类型被认为是完整的,并且允许sizeof (triangle)。或者你可以像评论中那样使用sizeof,但是使用类型而不是成员(指的是仅在C ++ 0x中允许的非静态成员):

//standard STL triangle data structure
struct triangle {
public:
    float n[3]; //normals, 4*3=12 bytes

    float x[3]; //first point of the triangle, 4*3=12 bytes
    float y[3]; //second point of the triangle, 4*3=12 bytes
    float z[3]; //third point of the triangle, 4*3=12 bytes

    long int a; //attributes, 2 bytes

    static int size() { return sizeof(triangle); } // this way
    static const int size = sizeof(float[3])*4 + sizeof(long int); // or this way
};

然而,第二种方式并不好,因为您在添加成员时很容易忘记更新它。

答案 1 :(得分:2)

额外问题:看看__attribute__((packed))

答案 2 :(得分:-1)

在我看来,使用文件i / o(特别是二进制)的流程是非常讨厌的。如果我是你,我宁愿只使用旧的C函数,如fopen和fread。

此外,文件的内存映射是一种给予太少爱的技术,IMO。我不知道任何支持它的标准/可移植库,但是如果你在Windows上我建议检查this MSDN article