简体   繁体   English

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

[英]Reading binary data without reinterpret_cast

Just because I've never read binary files before I wrote a program that reads binary STL files. 仅仅因为我在编写读取二进制STL文件的程序之前从未读过二进制文件。 I use ifstream s read member that takes a char* a parameter. 我使用ifstream的读取成员获取char *参数。 To cast my struct to a char* I use a reinterpret_cast. 要将我的结构转换为char *,我使用reinterpret_cast。 But as far as I remember every book about C++ I read said something like "don't use reinterpret_cast except you have to". 但据我记得每本关于C ++的书我读到的都说“不要使用reinterpret_cast,除非你必须”。 What would be a better way read binary data, not necessarily direct, but at last into a struct and without reinterpret_cast? 什么是更好的方式读取二进制数据,不一定是直接的,但最后到一个结构,没有reinterpret_cast?

The main function: 主要功能:

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

And the triangle struct 和三角形结构

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

(Extra question: #pragma pack(1) doesn't work with cygwins g++-4. How can I determine the size of the struct?) (额外的问题:#pragma pack(1)不适用于cygwins g ++ - 4.如何确定结构的大小?)

Well, that code looks fine. 好吧,那段代码看起来不错。 You are even caring about the padding issue. 你甚至关心填充问题。 I don't see how you can avoid casting here. 我看不出你怎么能避免在这里施展。 You can do this sequence: 你可以这样做:

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

But really, i don't do that in my code. 但实际上,我不会在我的代码中这样做。 It's just a more noisy way of doing a direct reinterpret_cast to char* . 这只是一种更为嘈杂的方式,可以直接对char* reinterpret_cast。 (See casting via void* instead of using reinterpret_cast ). (请参阅通过void *而不是使用reinterpret_cast进行转换 )。


The struct size can be determined using sizeof . 可以使用sizeof确定结构大小。 You just have to initialize the static member out of the class inside the .cpp (however, then the compiler doesn't know the value of ::size anymore and can't inline it). 您只需要在.cpp内的类中初始化static成员(但是,编译器不再知道::size的值,并且不能内联它)。
Alternatively, you can write it as a static inline member function. 或者,您可以将其编写为静态内联成员函数。 In its body, the class type is considered complete and sizeof (triangle) is allowed. 在它的主体中,类类型被认为是完整的并且允许sizeof (triangle) Or you can just use sizeof like you have in the comment, but use the type and not the members (referring to nonstatic members that way is allowed only in C++0x) : 或者您可以在注释中使用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
};

However, the second way is not nice since you can easily forget updating it when you add a member. 但是,第二种方式并不好,因为您在添加成员时很容易忘记更新它。

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

Using streams for file i/o (esp. binary) is just nasty in my opinion. 在我看来,使用文件i / o(特别是二进制)的流是非常讨厌的。 I'd rather just use the old C functions like fopen and fread if I were you. 如果我是你,我宁愿只使用旧的C函数,如fopen和fread。

Also, memory mapping of a file is a technique which is given too little love, IMO. 此外,文件的内存映射是一种给予太少爱的技术,IMO。 I don't know of any standard/portable libraries that support it, but if you're on Windows I suggest checking this MSDN article 我不知道任何支持它的标准/可移植库,但是如果你在Windows上我建议查看这篇MSDN文章

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM