Как я могу привести массив символов к указателю на функцию в C? - PullRequest
2 голосов
/ 15 декабря 2011

Можно ли при помощи приведения привести к указателю функции строку или массив символов и затем запустить его?

Я определил несколько функций int f1();, int f2(); и т. Д.

В функции main() я прочитал строку fct_name и объявил указатель на функцию int (*pv)();

Мне нужно сделать что-то вроде этого:

fct_name может иметь значения "f1", "f2" и т. Д.

pv = (some sort of cast)fct_name;

pv();

Суть в том, что я хочу избегать условных инструкций в пользу прямого назначения (потому что в моей программе большое количество функций)

Код, очевидно, должен работать.

Ответы [ 3 ]

1 голос
/ 15 декабря 2011

Вариант ответа Кэри, если вы работаете в системе * nix.dlopen() открывает вашу библиотеку.RTLD_LAZY говорит загрузчику не пытаться сразу разрешить все символы библиотеки и ждать, пока вы попытаетесь получить к ним доступ.dlsym() ищет рассматриваемый символ.

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

#include <dlfcn.h>

int main(int argc, char *argv[])
{
    void *handle = dlopen("libexample.so", RTLD_LAZY);
    if (handle == NULL) {
        // error
    }

    char fct_name[64];

    // read input from terminal here

    void *func = dlsym(handle, fct_name);

    if (func != NULL) {
        // call function here; need to cast as appropriate type
    }
}

libexample.so будет библиотекой сваши функции, скомпилированные как разделяемая библиотека, вот так:

gcc -Wall -o libexample.so example.c -shared -fPIC

При этом, если вы собираетесь скомпилировать разделяемую библиотеку, как это, вы, вероятно, просто захотите вызватьфункции в вашем бинарном.Это можно сделать, если вы связываете свою библиотеку во время компиляции:

gcc -Wall -o test test.c -L. -lexample

-L. говорит компоновщику искать библиотеки в текущем каталоге (.), а -lexample сообщает емуссылка с библиотекой с именем "libexample.so".Если вы сделаете это, вы можете просто вызывать библиотечные функции прямо в вашей программе.

1 голос
/ 15 декабря 2011

Если у вас нет внешней библиотеки и вы пытаетесь вызвать функции, объявленные в вашем исполняемом файле, вы можете выполнить поиск самостоятельно

#define REGISTER_FUNC(name)  {#name, name}

struct funclist
{
    const char* name;
    void (*fp)(void);  //or some other signature
};

struct funclist AllFuncs[] = {
    REGISTER_FUNC(f1),
    REGISTER_FUNC(f2),
    REGISTER_FUNC(f3),
    {NULL,NULL}  //LAST ITEM SENTINEL
 };

Теперь вы можете искать переменную fct_name в AllFuncs. Вы можете использовать линейный поиск, если число мало, или вставить их все в хеш-таблицу для поиска O (1).

С другой стороны, если ваши имена действительно f1, f2 и т. Д., Вы можете просто сделать

   void (*FuncList)(void)[]  = {NULL, f1,f2,f3};
   ...
   int idx = atol(fct_name+1);
   if (idx && idx < MAX_FUNCS)  
       FuncList[idx]();
0 голосов
/ 15 декабря 2011

Вы не можете привести массив символов к функции только потому, что массив содержит имя функции.Что вам нужно сделать, это поместить ваши функции в DLL, а затем сделать это:

HMODULE dll = LoadLibrary("foo.dll");
pv func = (pv)GetProcAddress(module, fct_name);
...