Создание указателей на функции, созданные во время выполнения - PullRequest
4 голосов
/ 08 января 2010

Я хотел бы сделать что-то вроде:

for(int i=0;i<10;i++)
    addresses[i] = & function(){ callSomeFunction(i) };

По сути, наличие массива адресов функций с поведением, связанным со списком чисел.

Если это возможно с внешними классами, такими как Boost. Лямбда в порядке.

Изменить: после некоторого обсуждения я пришел к выводу, что я не был достаточно явным. Пожалуйста, прочитайте Создание указателей на функции, созданные во время выполнения


В конце концов, я действительно хочу сделать:

class X
{
    void action();
}

X* objects;

for(int i=0;i<0xFFFF;i++)
    addresses[i] = & function(){ objects[i]->action() };


void someFunctionUnknownAtCompileTime()
{

}

void anotherFunctionUnknowAtCompileTime()
{

}

исправление someFunctionUnknownAtCompileTime () со сборкой для перехода к функции по адресам [0]

исправление anotherFunctionUnknownAtCompileTime () со сборкой для перехода к функции по адресам [1]

sth, я не думаю, что ваш метод будет работать из-за того, что они не являются реальными функциями, но я плохо объясняю, что я хочу делать.

Ответы [ 7 ]

3 голосов
/ 08 января 2010

Если я вас правильно понимаю, вы пытаетесь заполнить буфер машинным кодом, сгенерированным во время выполнения, и получить указатель функции на этот код, чтобы вы могли его вызвать.

Это возможно, но сложно. Вы можете использовать reinterpret_cast<>, чтобы превратить указатель данных в указатель на функцию, но вам нужно убедиться, что память, выделенная для вашего буфера, помечена как исполняемая операционной системой. Это будет включать системный вызов (LocalAlloc() в Windows iirc, не помню в Unix), а не «простой ванильный» вызов malloc / new.

Предполагая, что у вас есть исполняемый блок памяти, вы должны убедиться, что ваш машинный код учитывает соглашение о вызовах, указанное указателем функции, который вы создаете. Это означает нажатие / извлечение соответствующих регистров в начале функции и т. Д.

Но как только вы это сделаете, вы сможете использовать указатель на функцию, как и любую другую функцию.

Возможно, стоит посмотреть на JVM с открытым исходным кодом (или Mono), чтобы увидеть, как они это делают. В этом суть компиляции JIT.

2 голосов
/ 08 января 2010

Вот пример, который я только что взломал:

int func1( int op )
{
   printf( "func1 %d\n", op );
   return 0;
}
int func2( int op )
{
   printf( "func2 %d\n", op );
   return 0;
}

typedef int (*fp)(int);


int main( int argc, char* argv[] )
{
    fp funcs[2] = { func1, func2 };
    int i;

    for ( i = 0; i < 2; i++ )
        {
        (*funcs[i])(i);
        }

}
1 голос
/ 08 января 2010

Самый простой способ - создать группу из boost::function объектов:

#include <boost/bind.hpp>
#include <boost/function.hpp>
// ...

std::vector< boost::function<void ()> > functors;
for (int i=0; i<10; i++)
   functors.push_back(boost::bind(callSomeFunction, i));

// call one of them:
functors[3]();

Обратите внимание, что элементы вектора являются не "реальными функциями", а объектами с перегрузкой operator(). Обычно это не должно быть недостатком и на самом деле проще в обращении, чем реальные указатели функций.

0 голосов
/ 08 января 2010

Насколько я понимаю, вы пытаетесь создавать функции во время выполнения (так же, как мы можем это сделать в Ruby). Если это и есть намерение, я боюсь, что это невозможно в скомпилированных языках, таких как C ++. Примечание: если мое понимание вопроса неверно, пожалуйста, не понижайте голос:)

0 голосов
/ 08 января 2010

Вы не можете вызывать функцию-член без указателя this. Все экземпляры класса имеют функцию, хранящуюся в одном месте в памяти. Когда вы вызываете p->Function(), значение p сохраняется где-то (не помню, является ли он регистром или стеком), и это значение используется в качестве базового смещения для вычисления местоположений переменных-членов.

Таким образом, это означает, что вы должны сохранить указатель функции и указатель на объект, если вы хотите вызвать функцию для него. Общая форма для этого будет выглядеть примерно так:

class MyClass {
  void DoStuf();
};

//on the left hand side is a declaration of a member function in the class MyClass taking no parameters and returning void.
//on the right hand side we initialize the function pointer to DoStuff
void (MyClass::*pVoid)() = &MyClass::DoStuff;

MyClass* pMyClass = new MyClass();
//Here we have a pointer to MyClass and we call a function pointed to by pVoid.
pMyClass->pVoid();
0 голосов
/ 08 января 2010

Это в основном то, что сказано выше, но изменение вашего кода будет выглядеть примерно так:

std::vector<int (*) (int)> addresses;
for(int i=0;i<10;i++) {
     addresses[i] = &myFunction;  
}

Мне не совсем понятно, что вы имеете в виду, когда говорите, что функции создаются во время выполнения ... Я не думаю, что вы можете создать функцию во время выполнения, но вы можете назначить, какие указатели функций помещаются в ваш массив / вектор во время выполнения. Помните, что при использовании этого метода все ваши функции должны иметь одну и ту же сигнатуру (один и тот же тип возвращаемого значения и параметры).

0 голосов
/ 08 января 2010

Это можно сделать, просто предварительно определив эти функции по некоторым произвольным именам в глобальной области видимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...