1

I am currently working on a game project and i am saving a struct with all needed values of a game-object into a file. Saving is completely fine but if i start loading them in it will only load the first 25 of them. After that i tried with using a while (true) that loads in objects until the last object doesn't get the right type and break out of the loop. This works perfectly fine but is maybe not the most elegant solution to take.level-data.file

using namespace std;
struct{
    const char* type;
    int sizeW;
    int sizeH;
    int collisionLayer;
    int textureID;
    int positionX;
    int positionY;
} loadStruct;

ifstream fileObj;
fileObj.open("level.txt");
if (fileObj.is_open()){
    while (!fileObj.eof()){
        fileObj.read((char*)&loadStruct, sizeof(loadStruct));
        // creating my object out of loadStruct -> working fine
    }
    fileObj.close();
}

I've tried to remove the check for eof() and simply put a try/catch in the while loop breaking out if error is catched but this idea was not the most elegant and didn't work 100% of the time.

BigAgg
  • 31
  • 4
  • Removing the EOF check is the right idea, but you need to replace it with something. See [Why is iostream::eof inside a loop condition (i.e. `while (!stream.eof())`) considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-i-e-while-stream-eof-cons) for details. – user4581301 Nov 15 '22 at 22:12
  • Also a good idea to put the reader code in a function. It won't compile outside of one. – user4581301 Nov 15 '22 at 22:13
  • Are you sure the saving is completely fine? If the error is always occurring when reading in the last object, it would suggest that perhaps something isn't quite right when saving the last object? If it's saved to a text file, is there perhaps a missing closing bracket or some such? Have a look closely at the saved data. – Noscere Nov 15 '22 at 22:13
  • 1
    You are saving and restoring a `const char*` => that's not going to work. – Ted Lyngmo Nov 15 '22 at 22:14
  • 2
    When you `write` a pointer, you literally write the address and not the data pointed at. Odds are strong you'll need to serialize rather than just a blind binary dump. – user4581301 Nov 15 '22 at 22:14
  • 1
    Remember that the compiler is allowed to put padding bytes between members and at the end of structs. And you don't know if it does that - you have to serialise and desirialize your data in a way that doesn't rely on padding. – Jesper Juhl Nov 15 '22 at 22:16
  • @TedLyngmo thanks for "pointing" it out. Thats why i have to create new levels to load and save after making changes and compiling new ... – BigAgg Nov 15 '22 at 22:18
  • In the image you posted, how many bytes per pointer (first element). How many bytes for an `int`? Is your platform storing Big Endian or Little Endian? You may want to identify which bytes correspond to the fields in your struct. (Or just get rid of the image). – Thomas Matthews Nov 15 '22 at 22:19
  • 2
    A practical method for writing C-Style strings is to write the length first, then block write the text. Upon reading, read the quantity, then allocate memory, then block read from file into the allocated memory. – Thomas Matthews Nov 15 '22 at 22:20
  • @Noscere It works fine, if i put the type as "empty" before loading the struct and checking type after reading for being "empty" i can indeed load all objects out of a file, doesn't matter if there are 100.000 or 10. But if i use eof() it will always stop at the 25th struct im loading. – BigAgg Nov 15 '22 at 22:22
  • Writing pointers is not a good idea. There is no indication that the OS will place your program at the same location in memory. Also, there is no guarantee that another task or the OS will overwrite where your data was (so your pointer is pointing to garbage). – Thomas Matthews Nov 15 '22 at 22:23
  • 1
    @BigAgg You failed to open your file in binary mode, but you are doing binary I/O. that might explain the results you are seeing. – john Nov 15 '22 at 22:29
  • @BigAgg If you write the pointer to file and read it up from the file again (during the same program execution), chances are that your program still has the string in memory (at the "old" place) so it just looks like it's working. It is however not. If `type` is pointing at `"empty"`, write the `struct` down to file and then look in the file. You won't see the `empty` in there. – Ted Lyngmo Nov 15 '22 at 22:29
  • John probably just nailed it. Some implementations will stop dead if they find what they see as an EOF character in the data and this fake EOF character could simply be a byte in an `int`, `float`, or whatever that just happens to contain the same bit pattern as the system's EOF character. – user4581301 Nov 15 '22 at 22:40
  • Opening in binary mode won't help with the pointer and the data it's pointing at though. – Ted Lyngmo Nov 15 '22 at 22:43

1 Answers1

1

Thanks for "pointing" me to the char* type ... that was seriously the problem causing it to fail. Now i reworked it and also got rid of .eof() and simply check if my type was written or not.

using namespace std;

struct {
    char type[20];
    int sizeW;
    int sizeH;
    int collisionLayer;
    int textureID;
    int positionX;
    int positionY;
} loadStruct;

bool reading = true;
ifstream fileObj;
fileObj.open(filename);
if (fileObj.is_open()){
    while (reading){
        string str = "empty";
        strcpy(loadStruct.type, "empty");
        fileObj.read((char*)&loadStruct, sizeof(loadStruct));
        if (loadStruct.type == str){
            reading = false;
            break;
        }
    }
}
fileObj.close();
BigAgg
  • 31
  • 4
  • Should solve most problems you'll run into in the short term, but watch out! `int` changes size on different platforms. Only the minimum size , 16 bits`, is guaranteed. Usually you see 32 bit int and sometimes 64 bit, but you need to be careful if the file will be read by different platforms. You also have to watch out for the endian, byte order, changing. – user4581301 Nov 15 '22 at 23:37