Чтение двоичных данных без reinterpret_cast - PullRequest
8 голосов
/ 01 марта 2010

Просто потому, что я никогда не читал двоичные файлы, прежде чем написал программу, которая читает двоичные файлы STL. Я использую ifstream s член чтения, который принимает 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 ]

6 голосов
/ 01 марта 2010

Ну, этот код выглядит хорошо. Вы даже заботитесь о проблеме заполнения. Я не понимаю, как вы можете избежать кастинга здесь. Вы можете сделать эту последовательность:

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

Но на самом деле, я не делаю этого в своем коде. Это просто более шумный способ сделать прямой reinterpret_cast на char*. (См. приведение через void * вместо использования 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
};

Однако второй способ не очень приятен, поскольку вы легко можете забыть обновить его при добавлении участника.

2 голосов
/ 01 марта 2010

Дополнительный вопрос: взгляните на __attribute__((packed)).

0 голосов
/ 01 марта 2010

Использование потоков для файлового ввода / вывода (особенно двоичного), на мой взгляд, просто противно. Я бы предпочел просто использовать старые функции C, такие как fopen и fread, если бы вы были вами.

Кроме того, отображение памяти в файле - это метод, которому уделяется слишком мало любви, ИМО. Я не знаю ни одной стандартной / переносимой библиотеки, которая бы его поддерживала, но если вы работаете в Windows, я предлагаю проверить эту статью MSDN

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...