Действительно ли возможно вызвать функцию C, данную ее имя как строка?

Я видел этот вопрос в одной из загадок C!! Это действительно возможно?

Как я могу вызвать функцию, данную ее имя как строка? действительно ли возможно использовать строку, которая читается с scanf использоваться непосредственно для вызывания функции?

я уже думал, если (strcmp (ул., "строка")) затем вызывают функцию.

но есть ли какой-либо другой подход?

6
задан mipadi 2 February 2010 в 14:50
поделиться

7 ответов

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

typedef void (*foo)();
struct puzzleFoo{
   char *function_name;
   foo *fn;
};

Создать таблицу поиска на основе структуры, используя строковый параметр

struct puzzleFoo *Lookup(const char *function_name);

Затем выполнить итерацию по массиву/списку в поисках puzzleFoo's function_name и выполнить указатель функции с именем fn.

11
ответ дан 8 December 2019 в 02:45
поделиться

Да, иногда.

Под Linux вы можете использовать DLOPEN () , чтобы либо открыть общую библиотеку, содержащую нужную работу функции, либо даже доступа к текущему исполняемому исполняемому, и найдите свою функцию, используя DLSYM

. ] В Windows вы обычно называли LoadLibrary () и GetProcaddress () соответственно.

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

Кроме того, не забывайте, если вы Библиотека написана на C ++, то вам может придеться содержать с именем Cangling. Вам необходимо понять метод Mangling, используемый компилятором, используемым перед лицом этого.

3
ответ дан 8 December 2019 в 02:45
поделиться

Это зависит от какой функции, которую вы хотите позвонить.
Если это функция из DLL или другого типа экспортированного двоичного двоина - конечно, вы можете.
Для этого есть обычный API.
Если эта функция не экспортируется и была составлена ​​в исполняемости - конечно, не так, как такая информация, как имена функций функции.

2
ответ дан 8 December 2019 в 02:45
поделиться

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

VXWorks делает это для его встроенной оболочки.

3
ответ дан 8 December 2019 в 02:45
поделиться

Вы можете быть подлым:

if (strcmp (fn, "function1") == 0) function1();
if (strcmp (fn, "function2") == 0) function2();
if (strcmp (fn, "function3") == 0) function3();

или использовать dlopen и dlsym (или эквивалент) в зависимости от вашего окружения исполнения, но они не являются стандартными C, так что это может быть не опцией.

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

3
ответ дан 8 December 2019 в 02:45
поделиться
4349497-

Я написал это из моей головы - нет гарантии, что она будет даже компилировать, но, вероятно, довольно близко. Достаточно хорошо для интервью.

#include <stdio.h>
#include <unistd.h>
char *program = "#include<stdio.h>\
\
void Func1() { printf("hi\n"); }\
void Func2() { printf("hello\n"); }\
void Func3() { printf("hey\n"); }\
main() {\
";
char *program1 = "}\n";

static in ContainsFunction(char *func)
{
    char *match = strstr(func, program);
    if (!match || match - program < 5)
        return 0;
    int len = strlen(func);
    return strcmp(match-5, program) == 0 && match[len + 1] == '(' && isalnum(func[len-1]);
}

static void Compile(char *prog)
{
    pid_t pid = fork();
    if (pid == 0) {
        execl("/usr/bin/gcc", "gcc", prog, (char *)0);
    }
    else if (pid < 0) { printf("fork fail\n"); }
    else {
        pid_t ws = wait();
    }
 }

 static void Execute(char *prog)
 {
    pid_t pid = fork();
    if (pid == 0) {
        execl(prog, prog, (char *)0);
    }
    else if (pid < 0) { printf("fork fail\n"); }
    else {
        pid_t ws = wait();
    }
 }

static void CallFunction(char *funcname)
{
    FILE *fp = fopen("foo.c", "w");
    fputs(program, fp);
    fprintf(fp, "\t%s();\n", funcname);
    fputs(fp, program1);
    fclose(fp);

    Compile("foo.c");
    Execute("a.out");
}

int main()
{
    char funcname[8192]; /* too small, fail */
    puts("Who ya gonna call?");
    gets(funcname);
    if (ContainsFunction(funcname)) { CallFunction(funcname)); }
    else { printf("fail - no function %s\n", funcname); }
}    
1
ответ дан 8 December 2019 в 02:45
поделиться

В POSIX.1-2001 вы должны использовать dlopen () и dlsym () . В Windows используйте GetModuleHandleEx () и GetProcAddress () .

Вот дословный пример из руководства, который загружает функцию с именем «cos» из математической библиотеки и определяет косинус 2,0:

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int
main(int argc, char **argv)
{
   void *handle;
   double (*cosine)(double);
   char *error;

   handle = dlopen("libm.so", RTLD_LAZY);
   if (!handle) {
       fprintf(stderr, "%s\n", dlerror());
       exit(EXIT_FAILURE);
   }

   dlerror();    /* Clear any existing error */

   /* Writing: cosine = (double (*)(double)) dlsym(handle, "cos");
      would seem more natural, but the C99 standard leaves
      casting from "void *" to a function pointer undefined.
      The assignment used below is the POSIX.1-2003 (Technical
      Corrigendum 1) workaround; see the Rationale for the
      POSIX specification of dlsym(). */

   *(void **) (&cosine) = dlsym(handle, "cos");

   if ((error = dlerror()) != NULL)  {
       fprintf(stderr, "%s\n", error);
       exit(EXIT_FAILURE);
   }

   printf("%f\n", (*cosine)(2.0));
   dlclose(handle);
   exit(EXIT_SUCCESS);
}
10
ответ дан 8 December 2019 в 02:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: