Frage

I'm developing a application and my idea is store "apps" in files, like executables. Now i have that: AppWriter.c

#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
    std::vector<int> RandomStuff;
    std::vector<std::function<void()>> Functions;
    std::function<void()> MAIN;
} CODED;
void RANDOMFUNC()
{
    srand(time(NULL));
    for(int i = 0; i < 40; i++)
        CODED.RandomStuff.push_back(rand() % 254);
}
void LOGARRAY()
{
    for(int i = 0; i < CODED.RandomStuff.size(); i++)
        std::cout << "["<< i + 1 <<"]: "<< CODED.RandomStuff[i] << std::endl;
}
void PROGRAMMAIN()
{
    std::cout << "Hello i call random function!" << std::endl;
    CODED.Functions[0]();
    CODED.Functions[1]();
}
void main()
{
    CODED.MAIN = PROGRAMMAIN;
    CODED.Functions.push_back(RANDOMFUNC);
    CODED.Functions.push_back(LOGARRAY);
    std::cout << "Testing MAIN" << std::endl;
    CODED.MAIN();
    FILE *file = fopen("TEST_PROGRAM.TRI","wb+");
    fwrite(&CODED,sizeof(CODED),1,file);
    fclose(file);
    std::cout << "Program writted correctly!" << std::endl;
    _sleep(10000);
}

AppReader.c

#include <iostream>
#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
    std::vector<int> RandomStuff;
    std::vector<std::function<void()>> Functions;
    std::function<void()> MAIN;
} DUMPED;
void main()
{
    FILE *file = fopen("TEST_PROGRAM.TRI","rb+");
    fseek(file,0,SEEK_END);
    int program_len = ftell(file);
    rewind(file);
    fread(&DUMPED,sizeof(PROGRAM),1,file);
    std::cout 
        << "Function array size: " << DUMPED.Functions.size() << std::endl
        << "Random Stuff Array size: " << DUMPED.RandomStuff.size() << std::endl;
    DUMPED.MAIN();
}

When i run AppReader the functions dont work(Maybe why std::function it's like void pointers?), but in arrays or if i add variables i can see with debugger the data are storaged correctly (for that i tryed the vector of functions), but whatever doesn't work throw's me error on functional file. ¿Any ideas how i can do that?

War es hilfreich?

Lösung 2

Your problem is that you're storing information about functions that exist in one executable, then trying to run them in a separate executable. Other than that, your code does work, but as DeadMG says, you shouldn't be storing complex types in a file. Here's how I modified your code to prove that your code works if run within a single executable:

#include <iostream>
#include <vector>
#include <time.h>
#include <functional>
struct PROGRAM
{
  std::vector<int> RandomStuff;
  std::vector<std::function<void()>> Functions;
  std::function<void()> MAIN;
} CODED;
void RANDOMFUNC()
{
  srand(time(NULL));
  for(int i = 0; i < 40; i++)
     CODED.RandomStuff.push_back(rand() % 254);
}
void LOGARRAY()
{
  for(int i = 0; i < CODED.RandomStuff.size(); i++)
     std::cout << "["<< i + 1 <<"]: "<< CODED.RandomStuff[i] << std::endl;
}
void PROGRAMMAIN()
{
  std::cout << "Hello i call random function!" << std::endl;
  CODED.Functions[0]();
  CODED.Functions[1]();
}
int main()
{
  CODED.MAIN = PROGRAMMAIN;
  CODED.Functions.push_back(RANDOMFUNC);
  CODED.Functions.push_back(LOGARRAY);
  std::cout << "Testing MAIN" << std::endl;
  CODED.MAIN();
  FILE *file = fopen("TEST_PROGRAM.TRI","wb+");
  fwrite(&CODED,sizeof(CODED),1,file);
  fclose(file);
  std::cout << "Program writted correctly!" << std::endl;
  //      _sleep(10000);

  std::cout << "---------------------\n";

  file = fopen("TEST_PROGRAM.TRI","rb+");
  fseek(file,0,SEEK_END);
  int program_len = ftell(file);
  rewind(file);
  fread(&CODED,sizeof(PROGRAM),1,file);
  std::cout
     << "Function array size: " << CODED.Functions.size() << std::endl
     << "Random Stuff Array size: " << CODED.RandomStuff.size() << std::endl;
  CODED.MAIN();
}

The problem is not that you're storing complex types via binary read/write, per se. (Although that is a problem, it's not the cause of the problem you posted this question about.) Your problem is that your data structures are storing information about the functions that exist in your 'writer' executable. Those same functions don't even exist in your 'reader' executable, but even if they did, they likely wouldn't be at the same address. Your data structures are storing, via std::function, pointers to the addresses where the functions exist in your 'writer' executable. When you try to call these non-existent functions in your 'reader' executable, your code happily tries to call them but you get a segfault (or whatever error your OS gives) because that's not the start of a valid function in your 'reader' executable.

Now with regard to writing complex types (e.g. std::vector) directly to a file in binary format: Doing so "works" in the sample code above only because the binary copies of the std::vectors have pointers that, once read back in, still point to valid data from the original std::vectors which you wrote out. Note that you didn't write the std::vector's actual data, you only wrote their metadata, which probably includes things like the length of the vector, the amount of memory currently allocated for the vector, and a pointer to the vector's data. When you read that back, the metadata is correct except for one thing: Any pointers in it are pointing to addresses that were valid when you wrote the data, but which may not be valid now. In the case of the sample code above, the pointers end up pointing to the same (still valid) data from the original vectors. But there's still a problem here: You now have more than one std::vector that thinks they own that memory. When one of them is deleted, it will delete the memory that the other vector expects to still exist. And when the other vector is deleted, it will cause a double-delete. That opens the door to all kinds of UB. E.g. that memory could have been allocated for another purpose by that time, and now the 2nd delete will delete that other purpose's memory, or else the memory has NOT been allocated for another purpose and the 2nd delete may corrupt the heap. To fix this, you'd have to serialize out the essence of each vector, rather than their binary representation, and when reading it back in, you'd have to reconstruct an equivalent copy, rather than simply reconstitute a copy from the binary image of the original.

Andere Tipps

This is never going to work. At all. Ever. std::function is a complex type. Binary reads and writes don't work for complex types. They never can. You would have to ask for functions in a pre-defined serializable format, like LLVM IR.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top