Save and load function pointers to file

折月煮酒 提交于 2019-12-11 10:09:23

问题


Consider the following code:

typedef float (*MathsOperation)(float _1, float _2);
struct Data
{
    float x, y;
    MathsOperation op; 
};
Data data[100];

float Add(float _1, float _2){//add}
float Sub(float _1, float _2){//subtract}
float Mul(float _1, float _2){//multiply}
// other maths operations

for (int i = 0; i < 100; ++i)
{
    // assign one of the maths operators above to data struct member op
    // according to some condition (maybe some user input):
    if(condition1) data[i].op = &Add;
    if(condition2) data[i].op = &Sub;
    if(condition3) data[i].op = &Mul;
    // etc.
}

Now I'd like to somehow save the dataarray to a file and load it later (maybe in another program which doesn't know about the conditions that were used to assign the operators to each array element). Obviously, the pointers would be different every time I ran the application. So, my question is what is the best way to do this?


回答1:


You can't store "functions" as data anyway, and as you say, storing pointers in external media doesn't work. So, what you have to do in this case is store an operator value, e.g.

enum Operator
{ 
   Op_Add,
   Op_Sub,
   Op_Mul,
   Op_Largest    // For array size below.
};

And instead of:

if(condition1) data[i].op = &Add;
if(condition2) data[i].op = &Sub;
if(condition3) data[i].op = &Mul;

have:

if(condition1) data[i].op = Op_Add;
if(condition2) data[i].op = Op_Sub;
if(condition3) data[i].op = Op_Mul;

Since that is an integer type value, it can be stored in a file, and you can then do:

// Or `fin.read(reinterpret_cast<char*>(data), sizeof(data))
fin >> op >> x >> y; 

if (op == Op_Add) ... 
else if (op == Op_Sub) ... 

Or have a function pointer array that you index with op... In other words:

typedef float (*MathsOperation)(float _1, float _2);
...

MathsOperation mathsOps[Op_Largest] = { &Add, &Sub, &Mul };

...
mathsOps[op](x, y);
...



回答2:


If I where you I would build an index, where you could register your operators

static std::array<MathsOperation> MathsOperations;
MathsOperations.push_back(Add);
MathsOperations.push_back(Sub);
MathsOperations.push_back(Mul);

int getIdx(MathsOperation op) {
   return std::find(MathsOperations.begin(), MathsOperations.end(), op) - MathsOperations.begin();
}

and put it in a .h file just after the MathsOperation definitions

Then rather then saving the function pointer, you could just save the relevant index and access the operator afterwards

int           opidx = getIdx(Add);
MathsOperator op    = MathsOperator[idx];



回答3:


Non-portable, but almost certain to work if all your functions are in the same module:

template<typename FuncT>
intptr_t FunctionPointerToId( FuncT* fptr )
{
    return reinterpret_cast<intptr_t>(fptr) - reinterpret_cast<intptr_t>(&Add);
}

template<typename FuncT>
FuncT* FunctionPointerFromId( intptr_t id )
{
    return reinterpret_cast<FuncT*>(i + reinterpret_cast<intptr_t>(&Add));
}

This assumes that your implementation preserves relative addresses of functions within the same module (most platforms do guarantee this as implementation-specific behavior, since dynamic loaders rely on this). Using relative addresses (aka "based pointers") allows it to still work even if the module is a shared library that gets loaded at a different base address each time (e.g. ASLR).

Don't try this if your functions come from multiple modules, though.

If you have the ability to build and maintain a list of the functions, storing an index into that list is definitely a better approach (those indexes can remain good even after relinking, while relative code addresses get changed).




回答4:


You need some permanent identifier for each function. You save this identifier instead of function address and restore address after reading.

The simpliest is the integer identifier which is an index of array

const MathsOperation Operations[] = { &Add, &Sub };

In this case you must never change the order of Operations items.

If it is impossible, use strings:

const std::map<std::string, MathsOperation> OpNames
{
  { "Add", &Add },
  { "Sub", &Sub },
};


来源:https://stackoverflow.com/questions/28518367/save-and-load-function-pointers-to-file

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!