1

I want to save the state of my structs as a binary file and load them again. My structs look like this:

typedef struct
{
  uint8_t pointerLength;
  uint8_t *pointer;
  uint8_t NumBla;
  uinT16 Bla[MAX_NUM_Bla];
   ...
}
BAR_STRUCT, *BAR;

typedef struct
{
  int numBar;
  BAR bars[MAX_NUM_BAR];
}
FOO_STRUCT, *FOO;

Saving is no problem, but restoring the state. Iam at the point where the bytestring from the file is on the heap and a pointer is pointing to the first adress of this string. And I do as follows:

const void* dataPointer //points to adress in heap
unsigned char* bytePointer = (unsigned char*)dataPointer;

FOO foo = (FOO_STRUCT*)bytePointer;
bytePointer += sizeof(FOO_STRUCT);  

for (int i=0; i < MAX_NUM_BAR; i++) {
    foo->bars[i] = (BAR_STRUCT*)bytePointer;
}

The last assignment doesn't work and I get an EXC_BAD_ACCESS.
Because bars is an array of pointers i need to correct the adresses of each element is pointing to. Because they are not valid anymore. So I try to assign the adress of the object I saved in the bytesteam to foo->bars[i];
But I can not change foo->bars[i] at all. Accessing works but but assigning a new adress doesn't.
I wonder why.

Edit:
Iam working on OSX so to write bytes to file i use NSData:

bool saveCurrentState( FOO foo){
  NSMutableData *data = [NSMutableData data];
  [data appendBytes:templates length:sizeof(FOO_STRUCT)];
  for (int i=0; i < MAX_NUM_BAR; i++){
    [data appendBytes:&foo->bar[i] length:sizeof(INT_BAR_STRUCT)];
    if( foo->bar[i] != NULL )
      [data appendBytes:foo->bar[i]->pointer length:sizeof(uint8_t)*foo->bar[i]->length];
    ...
  }
}

I can't really change the structs since they are used in a lib, which i don't really have access too. I am especially interested in why it is not working as expected. As you can see I copy the whole struct including the pointer itself and adding the structures the pointer were pointing to to the byte string. Hope this give a bit more clarification.

When reading byte stream to setup the structs i just need the change the values of the array with the new address and that for some reason doesn't want to work.

Edit: Iam also saving/reading the file with NSData:

NSData* data = [NSData dataWithContentsOfFile:@"path/to/file"];
const void* dataPointer = [data bytes];
Schaltfehler
  • 140
  • 11
  • You say 'saving is no problem', but the BAR_STRUCT structure you're saving contains a `uint8_t *` member. What are you doing to avoid the inherent problems with saving a pointer value? The FOO_STRUCT structures contain an array of BAR_STRUCT pointers, too. Maybe you should show the problem-free saving code. It's weird (but legal) to write `FOO foo = (FOO_STRUCT *)bytePointer;` — surely it would be more self-consistent to write `FOO foo = (FOO)bytePointer;`? It might be clearer if you showed showed how you're reading the raw data into memory too. – Jonathan Leffler Nov 23 '12 at 05:05
  • Thanks for comment. I added the saving function. Yes you are right I could also write (FOO)bytePointer. I changed it for testing reason but i doesn't make any different the error stays the same. – Schaltfehler Nov 23 '12 at 06:48
  • This is confusing...it was tagged C++ (still is as I type), but you're using Objective-C to write. Why aren't you using NSData or NSMutableData to read too? – Jonathan Leffler Nov 23 '12 at 07:04
  • Because its not a Objective-C problem and i didn't wanted to confuse more than necessary ;-) The structs are part of cpp libary. with NSData i can write and read to/from files which i actually do by `const void* dataPointer = [data bytes];` – Schaltfehler Nov 23 '12 at 07:14

2 Answers2

2

Looks like what you are after is a serialization library. Try something like protocol buffers or tpl (choice depends on your exact needs, check the docs).

This previous question seems to do a decent job of covering some of the issues.

Community
  • 1
  • 1
Yaniv
  • 991
  • 6
  • 13
  • Thanks for the suggestion, but afaik tpl doesn't support nested structs, protocol buffers look interesting so far but i would like to solve it without extern libraries. – Schaltfehler Nov 23 '12 at 06:19
1

Apart from using serialization as @Yaniv suggests, what you can do is store everything in flat memory in order to avoid having embedded pointers to separate memory locations:

class Foo
{
private:
    // Prevent direct instantiation
    Foo();

    int numBar;

public:
    struct Bar
    {
        int pointerLength;
        int numBlas;
        uint16 blas[MAX_NUM_Bla];

        uint8* GetPointer()
        {
            return reinterpret_cast<uint8*>(this + 1);
        }
    };

    // Factory method
    static Foo* Create()
    {
        int totalSize = sizeof(Foo) + /* total size of all the Bars */;
        Foo* pFoo = reinterpret_cast<Foo*>(new char[totalSize]);

        ...
    }
};

Note that there's no longer a Bar::pointer member, but rather a Bar::GetPointer method. That's because what that pointer would point to will instead go right after the memory for Bar's members, so that everything is flat. Likewise, the array of Bars within Foo will go right after the memory for Foo's members.

user1610015
  • 6,561
  • 2
  • 15
  • 18
  • Thanks, thats a good idea. unfortunatly I can't really chage the structs itself since they are used in a library i can't change. – Schaltfehler Nov 23 '12 at 06:52