Sign in to follow this  
ChrisPepper1989

Help on File writing/loading why does sizeof(a struct) not seem to work?

Recommended Posts

Ive created some simple writing and loading functions for a map engine that im doing and there is one thing that puzels me about fwrite and fread. At the minute it works using this:
fwrite(MapData, sizeof(unsigned char), sizeof(this->MapData), filePTR);

...

result = fread(&MapData, sizeof(unsigned char) , TotalFileSize, filePTR);


however what puzels me is the sizeof(unsigned char), it only seems to work if i use this size of, and as i understand it, this parameter is meant for the size of one element in the array so to me it would make sense to have it as either: sizeof(MapData[0][0]) or sizeof(MapCoord) MapCoord being the struct im using for MapData, i.e. MapData is defined as MapCoord MapData[MAX_X][MAX_Z]. and the stuct is defined as: struct MapCoord{ int Height; int x,z; bool Trigger; aColour Colour; }; but for some reason whenever i try one of teh above 2 methods the file is saved completely blank! what is the reason for this? its not highly urgent as currently the system works but i just find it a bit puzzeling, this is the first time ive really used file handeling without using a pre-written function! also i fear that if i was to add more important data to MapCoord perhaps some of it wouldnt be loaded up, i know that int Height; int x,z; are definately being loaded up, but for as for the other two, theres no way for me to check. Any advice on this would be greatly appreciated! Thank you, chris

Share this post


Link to post
Share on other sites
sizeof(array) evaluates to the size of the array, in bytes, not the number of elements in the array.

You should be using:
fwrite(MapData, sizeof(MapCoord), MAX_X * MAX_Z, filePTR);

Or, better yet, boost::multi_array and boost::serialize, in order to work around file format bookkeeping and endianness problems.

Share this post


Link to post
Share on other sites
Quote:
Original post by ToohrVyk

You should be using:
fwrite(MapData, sizeof(MapCoord), MAX_X * MAX_Z, filePTR);


This works! now im even more confused, lol because whenever i use sizeof(MapCoord),sizeof(MapData) it writes nothing at all, but when i use
sizeof(unsigned char),sizeof(MapData) it works. yet
sizeof(MapCoord), MAX_X * MAX_Z, works! this looks more logical but why does this apear to work the same way as: sizeof(unsigned char),sizeof(MapData)? :-S

Quote:
Original post by ToohrVyk
Or, better yet, boost::multi_array and boost::serialize, in order to work around file format bookkeeping and endianness problems.


exactly what are they? ive never heard of "boost".

Thank you for your help, Chris

Share this post


Link to post
Share on other sites
sizeof(MapData) is size of one element * number of element (default 1 if it is not an array)

so sizeof(MapData) will be Grater than MAX_X * MAX_Z
then the overspace will be filled w/ memory junks i meant :
sizeof(MapData)-MAX_X * MAX_Z oversize

please read more about sizeof().

take care. ^^


Share this post


Link to post
Share on other sites
Quote:
Original post by ChrisPepper1989
This works! now im even more confused, lol because whenever i use sizeof(MapCoord),sizeof(MapData)


This would attempt to write sizeof(MapData) values of the same size as MapCoord, which is clearly more than you've got in your array (because the size is the number of bytes, which is always greater than the number of values). So, the operation overflows and you can't really expect anything sane to happen.

Quote:
sizeof(MapCoord), MAX_X * MAX_Z, works!


This attempts to write as many values of the same size as MapCoord as there are in MapData (which means writing them all).

Quote:
but why does this apear to work the same way as: sizeof(unsigned char),sizeof(MapData)? :-S


Because this writes as many bytes as there are in MapData. It's the same as the previous one except that, instead of writing things structure by structure, you're writing it byte by byte.

Quote:
exactly what are they? ive never heard of "boost".


Boost is a C++ library that is used a lot in the industry, because it provides very useful additions to the C++ standard library. Namely, boost::multi_array is a nice class for representing a multidimensional array without forcing a static size on it, and boost::serialize is a series of useful tools for writing data to and from a file without all the "keep track of bytes" nastiness.



Share this post


Link to post
Share on other sites
The arguments to fwrite() are:

(location where data starts, number of things to write, size of each thing being written, handle to file).


The reason 'sizeof(unsigned char)' works in your position is because the sizeof(unsigned char) is 1. Always. By definition. Writ in stone, in the standard..

Counting "the location where data starts" and "the number of things to write" is kind of redundant, but that's how it's set up.

But the word 'this->' means you are using C++, and in C++, you should be using C++'s I/O, in the absence of a damn good reason otherwise.

That means using a std::fstream object, from the library header <fstream>.

It is at least as easy to use as anything you're accustomed to, and in fact designed for familiarity, at least with binary I/O:


std::ofstream theFile("foo.dat", std::ios::binary);
// We don't have to say "fwrite"; it's just called 'write' because it's obvious
// we're writing to a file from the fact that theFile is an fstream.
// ('ofstream' is simply a kind of fstream, that's open for output by default;
// that avoids having to specify that part of the file mode explicitly.)
// Instead of a "magic" string specifying the file mode, we use flags.
// Because it's a member function, we don't have to pass theFile separately as
// a parameter.
// And there's no size of thing/number of things redundancy. All we have to do
// is respect C++'s slightly stronger type system, by casting the pointer.
// We'll use a new-style cast for that to be specific about our intent, and
// because casts *should be ugly and stand out*.
theFile.write(reinterpret_cast<char*>(MapData), sizeof(MapData));
// There is no need to close the file afterward, in normal use cases; this is
// handled automatically by the destructor of the fstream object.

// In a different part of the code, we can read the data similarly:
std::ifstream theFile("foo.date", std::ios::binary);
theFile.read(reinterpret_cast<char*>(MapData), sizeof(MapData));
// It's a very bad idea, BTW, to be using a static sized array and then trying
// to read "the whole file" in, blindly trusting that the file is the right size.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this