Я видел этот вопрос в одной из загадок C!! Это действительно возможно?
Как я могу вызвать функцию, данную ее имя как строка? действительно ли возможно использовать строку, которая читается с scanf использоваться непосредственно для вызывания функции?
я уже думал, если (strcmp (ул., "строка")) затем вызывают функцию.
но есть ли какой-либо другой подход?
Поскольку ни слова о том, что такое функция, ни о ее параметрах, я бы представил себе нечто подобное:
typedef void (*foo)(); struct puzzleFoo{ char *function_name; foo *fn; };
Создать таблицу поиска на основе структуры, используя строковый параметр
struct puzzleFoo *Lookup(const char *function_name);
Затем выполнить итерацию по массиву/списку в поисках puzzleFoo
's function_nam
e и выполнить указатель функции с именем fn
.
Да, иногда.
Под Linux вы можете использовать DLOPEN ()
, чтобы либо открыть общую библиотеку, содержащую нужную работу функции, либо даже доступа к текущему исполняемому исполняемому, и найдите свою функцию, используя DLSYM
. ] В Windows вы обычно называли
LoadLibrary ()
и GetProcaddress ()
соответственно.
Если таблицы символов для рассматриваемых библиотек были разделить или, в некоторых случаях, если методы являются статическими / частными, то вы не сможете получить доступ к ним, используя этот подход.
Кроме того, не забывайте, если вы Библиотека написана на C ++, то вам может придеться содержать с именем Cangling. Вам необходимо понять метод Mangling, используемый компилятором, используемым перед лицом этого.
Это зависит от какой функции, которую вы хотите позвонить.
Если это функция из DLL или другого типа экспортированного двоичного двоина - конечно, вы можете.
Для этого есть обычный API.
Если эта функция не экспортируется и была составлена в исполняемости - конечно, не так, как такая информация, как имена функций функции.
Если функция доступна в общей библиотеке, вы можете загрузить общую библиотеку во время выполнения и получить доступ к таблице символов, которая будет конвертирована для имен и указателей функций. Что касается убедиться, что подпись вызова функции верна, вы сами по себе.
VXWorks делает это для его встроенной оболочки.
Вы можете быть подлым:
if (strcmp (fn, "function1") == 0) function1();
if (strcmp (fn, "function2") == 0) function2();
if (strcmp (fn, "function3") == 0) function3();
или использовать dlopen
и dlsym
(или эквивалент) в зависимости от вашего окружения исполнения, но они не являются стандартными C, так что это может быть не опцией.
Это все, что у меня есть, кроме невероятно не портативного наполнения исполняемого файла или разработки отвратительных макросов (которые, скорее всего, сводятся к коллекции операторов , если
все равно показаны выше, или массиву указателей на функции, что-то вроде того).
Я написал это из моей головы - нет гарантии, что она будет даже компилировать, но, вероятно, довольно близко. Достаточно хорошо для интервью.
#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); }
}
В 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);
}