Reading binary data into struct with ifstream
31,215
Solution 1
As the comment above states, you are probably missing hdr.length and hdr.count. I tried it with gcc 4.8 and clang 3.5 and it works correctly.
#include <iostream>
#include <fstream>
#pragma pack(push, r1, 1)
struct Header {
char id[15];
int length;
int count;
};
#pragma pack(pop, r1)
int main() {
Header h = {"alalalala", 5, 10};
std::fstream fh;
fh.open("test.txt", std::fstream::out | std::fstream::binary);
fh.write((char*)&h, sizeof(Header));
fh.close();
fh.open("test.txt", std::fstream::in | std::fstream::binary);
fh.read((char*)&h.id, sizeof(h.id));
fh.read((char*)&h.length, sizeof(h.length));
fh.read((char*)&h.count, sizeof(h.count));
fh.close();
std::cout << h.id << " " << h.length << " " << h.count << std::endl;
}
Solution 2
It is also possible to read the struct in one step.
i.e. fh.read((char*)&h, sizeof(Header));
Author by
Dan
Updated on July 27, 2022Comments
-
Dan over 1 year
I'm trying to read binary data from a file using ifstream.
Specifically, I'm trying to populate this "Header" struct with data read from a file:
struct Header { char id[16]; int length; int count; };
Now, if I read the file in this way, the result is exactly what I want:
input.read((char*)&hdr, sizeof(hdr));
But if I instead read each variable of the struct manually, the results are gibberish:
input.read((char*)&hdr.id, sizeof(hdr.id)); input.read((char*)&hdr.length, sizeof(hdr.length)); input.read((char*)&hdr.count, sizeof(hdr.count));
My question is, what is happening here that makes these two methods return different results?
-
Chris McGrath about 10 yearsYou read into
length
andcount
, how have you defined them? Or, were they meant to behdr.length
andhdr.count
? -
WhozCraig about 10 yearsIf you think it relevant how you wrote the data to that file (or someone else did), you'd be right; it is so. Short answer:
sizeof(Header)
is required to be "at least" as big as the sum of the size of its members, and can be bigger when including implementation member padding. The members aren't guaranteed to be buttressed up against each other when writing the struct as a whole, yet you're reading it expecting they are. I.e. If you're "writing" a orange, trying to "read" a bag a tangerines isn't necessarily going to work. -
Dan about 10 years@ChrisMcGrath Sorry, that was a copy-paste error, fixed it now
-
Dan about 10 years@WhozCraig Are you saying that the first method of reading the data works and the second doesn't because there is padding between the variables within the struct? I don't know how this particular data was written, I only know how it's supposed to be read, so it's curious to me that it was written in such a way that the first method of reading it works perfectly.
-
WhozCraig about 10 years@Dan You "only know how its supposed to be read." And how is that ? The first method assumes whoever wrote this did it with the same layout and padding that you're using. If there is no padding issue, then the second will work (and is nearly the preferred way to do this to begin with, both for reading and writing). Given the layout and size of the data members in that struct, it would be odd if there were padding between elements, after the last element, or both, but I've seen odder things.
sizeof(hdr)
compared tosizeof()
each member will tell much. -
Dan about 10 years@WhozCraig Thanks, I'll look into the sizes of each and report back if I find anything weird. I did not write the file myself, so I don't know how it was written; and I only know how to read it because the code above is adapted from code someone else has given me - although strangely, they didn't write the file either, so I don't know how they figured it out. I just asked the question out of curiosity really, when I noticed that the 2 methods were behaving differently.
-
Dan about 10 yearsThe sizes match up... but it turns out my "copy-paste error" WAS actually present in the code, so that was the problem! The 2 methods now work identically :) Thanks for all your help.
-
WhozCraig about 10 years@Dan Don't count on it always being that way. You're fortunate neither padding nor endianess were an issue, because they usually are.
-
WhozCraig about 10 yearsChange the
id
field tochar id[15]
and run that again, just for kicks. -
Blaz Bratanic about 10 yearsYou are right. Added pragma directives to fix alignment.
-
Jean-Christophe over 3 yearsWith this method, care must be taken to avoid memory alignment padding. See Structure padding and packing
-
Jamie over 2 yearsThis would be much improved by handling byte order. If this is written on a big endian system and read on a small endian system, things would go poorly.