kzen.dev
  • Вопросы
  • Метки
  • Пользователи
Оповещения
Вознаграждения
Регистрация
После регистрации, сможете получать уведомления об ответах и комментариях на Ваши вопросы.
Вход
Если у Вас уже есть аккаунт, войдите чтобы проверить новые уведомления.
Тут будут вознаграждения за добавленные вопросы, ответы и комментарий.
Дополнительно
Источник
Редактировать
 wantobegeek
wantobegeek
Вопрос

Вызов функции, названной в строковой переменной в C

Я хочу вызвать функцию, используя переменную. Возможно ли это в C?

На самом деле, я хочу получить имя функции от пользователя и сохранить его в переменной. Теперь я хочу вызвать функцию, имя которой хранится в переменной. Может ли кто-нибудь подсказать мне, как это можно сделать в C?

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

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

50 2009-07-13T10:26:27+00:00 12
Josh Caswell
Josh Caswell
Редактировал вопрос 11-го августа 2013 в 3:20
Программирование
c
function
Решение / Ответ
Blair Conrad
Blair Conrad
13-го июля 2009 в 10:29
2009-07-13T10:29:38+00:00
Дополнительно
Источник
Редактировать
#9255895

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

41
0
 GManNickG
GManNickG
13-го июля 2009 в 10:33
2009-07-13T10:33:52+00:00
Дополнительно
Источник
Редактировать
#9255897

Лучшее, что вы можете сделать, это что-то вроде этого:

#include <stdio.h>

// functions
void foo(int i);
void bar(int i);

// function type
typedef void (*FunctionCallback)(int);
FunctionCallback functions[] = {&foo, &bar};

int main(void)
{
    // get function id
    int i = 0;
    scanf("%i", &i);

    // check id
    if( i >= sizeof(functions))
    {
        printf("Invalid function id: %i", i);
        return 1;
    }

    // call function
    functions[i](i);

    return 0;
}

void foo(int i)
{
    printf("In foo() with: %i", i);
}

void bar(int i)
{
    printf("In bar() with: %i", i);
}

Здесь для идентификации функций используются числа, а не строки, но для строк достаточно просто преобразовать строку в соответствующую функцию.

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

Edit

Что касается вашей правки, вы наверняка захотите воспользоваться ответом onebyone's.

Вы хотите, чтобы ваши пользователи собирали динамические библиотеки (это разделяемый объект [.so] в Linux, и библиотека динамических ссылок [.dll] в Windows).

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

 Community
Community
Редактировал ответ 23-го мая 2017 в 11:54
37
0
 Falaina
Falaina
13-го июля 2009 в 10:53
2009-07-13T10:53:31+00:00
Дополнительно
Источник
Редактировать
#9255901

Хотя это вовсе'т совсем практичное решение, бьюсь об заклад, вы, безусловно, могли вызывать функцию по строке, имея программы читать В он's собственное исполняемый файл и проанализировать таблицу символов. Таблица символов должен содержать имя функции, а также он's первый адрес инструкции. Тогда вы могли поместить этот адрес в функцию переменную-указатель и вызвать его.

Я думаю, я могу попробовать, что это.

Редактировать: пожалуйста, никто и никогда не напишу такой код, но вот как вы можете вызвать функцию, используя строку для Линукс бинарных эльф с целой таблицей символов (требуется libelf):

#include <fcntl.h>
#include <stdio.h>
#include <elf.h>
#include <libelf.h>
#include <stdlib.h>
#include <string.h>

void callMe() {
  printf("callMe called\n");
}

int main(int argc, char **argv) {
  Elf64_Shdr *    shdr;
  Elf64_Ehdr *    ehdr;
  Elf *        elf;
  Elf_Scn *    scn;
  Elf_Data *    data;
  int cnt;
  void (*fp)() = NULL;

  int fd = 0;

  /* This is probably Linux specific - Read in our own executable*/
  if ((fd = open("/proc/self/exe", O_RDONLY)) == -1)
    exit(1);

  elf_version(EV_CURRENT);

  if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {
    fprintf(stderr, "file is not an ELF binary\n");
    exit(1);
  }
    /* Let's get the elf sections */
    if (((ehdr = elf64_getehdr(elf)) == NULL) ||
    ((scn = elf_getscn(elf, ehdr->e_shstrndx)) == NULL) ||
    ((data = elf_getdata(scn, NULL)) == NULL)) {
      fprintf(stderr, "Failed to get SOMETHING\n");
      exit(1);
    }

    /* Let's go through each elf section looking for the symbol table */
    for (cnt = 1, scn = NULL; scn = elf_nextscn(elf, scn); cnt++) {
      if ((shdr = elf64_getshdr(scn)) == NULL)
    exit(1);

      if (shdr->sh_type == SHT_SYMTAB) {
    char *name;
    char *strName;
    data = 0;
    if ((data = elf_getdata(scn, data)) == 0 || data->d_size == 0) {
      fprintf(stderr, "No data in symbol table\n");
      exit(1);
    }

    Elf64_Sym *esym = (Elf64_Sym*) data->d_buf;
    Elf64_Sym *lastsym = (Elf64_Sym*) ((char*) data->d_buf + data->d_size);

    /* Look through all symbols */ 
    for (; esym < lastsym; esym++) {
      if ((esym->st_value == 0) ||
          (ELF64_ST_BIND(esym->st_info)== STB_WEAK) ||
          (ELF64_ST_BIND(esym->st_info)== STB_NUM) ||
          (ELF64_ST_TYPE(esym->st_info)!= STT_FUNC)) 
        continue;

      name = elf_strptr(elf,shdr->sh_link , (size_t)esym->st_name);

      if(!name){
        fprintf(stderr,"%sn",elf_errmsg(elf_errno()));
        exit(-1);
      }
      /* This could obviously be a generic string */
      if(strcmp("callMe", name) == 0 ) {
        printf("Found callMe @ %x\n", esym->st_value);
        fp = esym->st_value;
      }
    }    
    /* Call and hope we don't segfault!*/
    fp();
    elf_end(elf);
    return 0;
  }   
 Blub
Blub
Редактировал ответ 10-го мая 2012 в 12:21
27
0
Steve Jessop
Steve Jessop
13-го июля 2009 в 10:36
2009-07-13T10:36:53+00:00
Дополнительно
Источник
Редактировать
#9255898

Это's не возможно в чистом C, но вы можете играть трюки с DLL. Положить все функции, которые вы хотите, чтобы выбрать из в DLL-файл, а затем использовать функция dlsym (или GetProcAddress на Windows, или любой другой API-интерфейса системы), чтобы получить указатель на функцию по имени, и называть, используя которые.

Это не'т работать на некоторых платформах, либо потому, что они не'т иметь библиотеки на всех, или потому, что такие как Symbian функций в DLL может'т быть доступны по имени во время выполнения, только по номеру.

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

Steve Jessop
Steve Jessop
Редактировал ответ 13-го июля 2009 в 10:52
15
0
Sean Bright
Sean Bright
13-го июля 2009 в 5:11
2009-07-13T17:11:36+00:00
Дополнительно
Источник
Редактировать
#9255903
#include <stdio.h>
#include <string.h>

void function_a(void) { printf("Function A\n"); }
void function_b(void) { printf("Function B\n"); }
void function_c(void) { printf("Function C\n"); }
void function_d(void) { printf("Function D\n"); }
void function_e(void) { printf("Function E\n"); }

const static struct {
  const char *name;
  void (*func)(void);
} function_map [] = {
  { "function_a", function_a },
  { "function_b", function_b },
  { "function_c", function_c },
  { "function_d", function_d },
  { "function_e", function_e },
};

int call_function(const char *name)
{
  int i;

  for (i = 0; i < (sizeof(function_map) / sizeof(function_map[0])); i++) {
    if (!strcmp(function_map[i].name, name) && function_map[i].func) {
      function_map[i].func();
      return 0;
    }
  }

  return -1;
}

int main()
{
  call_function("function_a");
  call_function("function_c");
  call_function("function_e");
}
Sean Bright
Sean Bright
Редактировал ответ 13-го июля 2009 в 5:22
12
0
 Naveen
Naveen
13-го июля 2009 в 10:48
2009-07-13T10:48:55+00:00
Дополнительно
Источник
Редактировать
#9255900

Это то, что вы ищете:

void foo()
{
    printf("foo called\n");
}

void bar()
{
    printf("bar called\n");
}

int main()
{
    char fun[10] = {'\0'};

    printf("Enter function name (max 9 characters):");
    scanf("%s",fun);

    if(strcmpi(fun, "foo") == 0)
    {
    foo();
    }
    else if(strcmpi(fun, "bar") == 0)
    {
    bar();
    }
    else
    {
    printf("Function not found\n");
    }

    return 0;
}
2
0
 neuro
neuro
13-го июля 2009 в 10:42
2009-07-13T10:42:05+00:00
Дополнительно
Источник
Редактировать
#9255899

Как сказали другие, это правда, что c не имеет механизма отражения. Но вы можете добиться такого поведения с помощью динамически загружаемая библиотека/общая объекта. На самом деле вы можете загрузить динамическую библиотеку и затем вы можете вызывать функции в DLL/так с их именем ! Это не C и операционной системы конкретного, но, что's пути. Его используют функции выглядит в Linux и LoadLibrary на Windows. Вы можете найти библиотеки, которые делают работу для вас, как ГТК/Глеб.

2
0
 Erwan
Erwan
4-го апреля 2019 в 8:02
2019-04-04T08:02:21+00:00
Дополнительно
Источник
Редактировать
#9255906

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

Это'ы на ОС Linux Ubuntu, но к сожалению не на моей встроенной целевых руку. Я не'т знаю, почему, если это'ов зависит от glibc или версия libdl может.

На моей цели рукой, мысль ясна: " был./test8: не может динамически загружать исполняемый на".

В любом случае, код, который я использовал это.

Я скомпилировал с:

test8 ССЗ.с-ЛПНП -rdynamic

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

int TEST_MyTestFunction( char *pArgPos , int Size , char Param )
{
    printf("TEST_MyTestFunction\n");
    return 0;
}

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

    int(*func)(char *,int, char);

    handle = dlopen(argv[0], RTLD_LAZY);
    dlerror();

    func = (int(*)(char *,int, char)) dlsym(handle, "TEST_MyTestFunction");

    error = dlerror();

    char *p1 = "param1";
    int p2 = 5;
    int p3 = 'A';

    ret = func(p1, p2, p3);

    return ret;
}
1
0
Martin Liversage
Martin Liversage
13-го июля 2009 в 10:32
2009-07-13T10:32:01+00:00
Дополнительно
Источник
Редактировать
#9255896

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

Такие языки, как C# и Java, поддерживают отражение, что упрощает выполнение позднего связывания.

1
0
Jose Quinteiro
Jose Quinteiro
2-го ноября 2016 в 6:38
2016-11-02T06:38:05+00:00
Дополнительно
Источник
Редактировать
#9255904

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

Во-первых, вы'll найти кучу мест в Интернете (включая Википедию), который скажет вам, что способ открыть свой главный программы как библиотека является вызов функции выглядит(3) наподобие этой функции выглядит(нуль, 0)`. Это не будет работать для glibc-за привязки флаг должен быть указан, как на man-странице четко сказано:

один из следующих двух значений должен быть включен в флаг:<БР /> RTLD_LAZY<БР /> выполнять позднее связывание. Только разрешить символы в качестве кода...<БР /> флагом rtld_now<БР /> если это значение не указано, или переменную окружения...

Я не'т думаю, что вы выберете здесь важно, потому что вы'вновь собирается связать все символы из статической библиотеки в исполняемый файл.

Это подводит нас к следующей проблеме. Компоновщик не будет включать в себя символы из статической библиотеки в исполняемый файл, потому что они'повторно не ссылается. Путь, чтобы заставить компоновщик GNU в любом случае включать символов -от WL,--все-архиве путь/к/статический/Либ.а-от WL,--нет-все-архиве, как этот ответ описывает. Путь, чтобы заставить компоновщик Мак ОС Х, чтобы включать все символы из статической библиотеки-ЧШ,-force_load путь/к/статический/Либ.а`.

 Community
Community
Редактировал ответ 23-го мая 2017 в 12:02
1
0
 Oktaheta
Oktaheta
30-го сентября 2017 в 6:50
2017-09-30T06:50:49+00:00
Дополнительно
Источник
Редактировать
#9255905

Введение в nginx-c-функции. Это модуль nginx, которые позволят вам связать свой .поэтому(с/C++) приложения в контексте сервера и вызвать функцию .поэтому применение в директиве location. Вы можете реализовать nginx и обмениваться данными кэш-памяти через функцию nginx и с(https://github.com/Taymindis/nginx-c-function/wiki/Nginx-Cache-Data-via-nginx-c-function). Это для разработчиков, которые любят хозяина сервера c. https://github.com/Taymindis/nginx-c-function

Введите описание изображения здесь

 Oktaheta
Oktaheta
Редактировал ответ 5-го марта 2018 в 1:55
0
0
Анонимный пользователь
13-го июля 2009 в 4:52
2009-07-13T16:52:25+00:00
Дополнительно
Источник
Редактировать
#9255902

Массивы C # можно индексировать только с целыми типами. Так пишете хэш-таблицу сопоставления строк с указателями функций.

Он также может быть стоит посмотреть на объект в Python, Lua и других языков скрипт для размещения их во время выполнения в программе c: части кода С, то можно работать со скриптовым языком.

АЛТ'лы, у некоторых людей код расширения языка сценариев в с. Затем они могут иметь скорость &ампер; низкий уровень доступа к C в их сценарии.

Вы собираетесь найти, рано или поздно, что с помощью динамически типизированный язык сценарий фразеологизмы - как функцию eval(), и размытые линии между функцию и имя функции, и код, который зависит от ДОЦ массивы в C можно, но в конечном итоге больно.

0
0
Добавить вопрос
Категории
Все
Технологий
Культура / Отдых
Жизнь / Искусство
Наука
Профессии
Бизнес
Пользователи
Все
Новые
Популярные
1
Ilya Smirnov
Зарегистрирован 5 дней назад
2
Денис Васьков
Зарегистрирован 1 неделю назад
3
Dima Patrushev
Зарегистрирован 1 неделю назад
4
sirojidddin otaboyev
Зарегистрирован 2 недели назад
5
Елена Гайдамамакинат
Зарегистрирован 2 недели назад
ID
KO
RU
© kzen.dev 2023
Источник
stackoverflow.com
под лицензией cc by-sa 3.0 с атрибуцией