Een functie aanroepen met de naam in een stringvariabele in C

Ik wil een functie aanroepen met een variabele. Kan dat in C?

Wat ik eigenlijk wil doen, is de functienaam van de gebruiker ophalen en opslaan in een variabele. Nu wil ik de functie aanroepen waarvan de naam is opgeslagen. Kan iemand mij vertellen hoe dit kan in C?

Ik wil een AI-game-engine ontwikkelen voor een game voor twee spelers. Twee programma’s zonder hoofdfunctie die de logica voor het winnen van het spel implementeren, worden naar de game-engine gevoerd.
Laat me duidelijk zijn dat de programmanamen hetzelfde zullen zijn als die van de priemfuncties in het programma die de logica implementeren om het spel te winnen.

Dus als de gebruiker de naam van de eerste en tweede speler invoert, kan ik ze in 2 verschillende variabelen opslaan. Omdat de namen van de primaire functies hetzelfde zijn als die van de programmanamen, ben ik van plan de functies aan te roepen met variabelen die de prog-namen bevatten.


Antwoord 1, autoriteit 100%

C ondersteunt dit soort bewerkingen niet (talen met reflectie zouden dat wel doen). Het beste wat u kunt doen, is een opzoektabel maken van functienamen tot functieaanwijzers en die gebruiken om erachter te komen welke functie u moet aanroepen. Of je kunt een switch-statement gebruiken.


Antwoord 2, autoriteit 88%

Het beste wat je kunt doen is zoiets als dit:

#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);
}

Dit gebruikt getallen in plaats van tekenreeksen om de functies te identificeren, maar als u het met tekenreeksen doet, hoeft u alleen maar de tekenreeks om te zetten in de juiste functie.

Wat ben je precies aan het doen? Gewoon uit nieuwsgierigheid, hier ga je, maar als je een probleem hiermee probeert op te lossen, weet ik zeker dat er een manier is die beter geschikt is voor je taak.

Bewerken

Als je je zorgen maakt over je bewerking, kun je het beste gebruik maken van onebyone’santwoord, zeker.

U wilt dat uw gebruiker dynamische bibliotheken bouwt (dat is een gedeeld object [.so] in Linux en een dynamische linkbibliotheek [.dll] in Windows).

Als je dat eenmaal hebt gedaan en ze je de naam van hun bibliotheek geven, kun je het besturingssysteem vragen die bibliotheek voor je te laden en een verwijzing naar een functie binnen die bibliotheek opvragen.


Antwoord 3, autoriteit 76%

Hoewel dit niet echt een praktische oplossing is, wed ik dat je een functie zeker met een string kunt aanroepen door een programma zijn eigen uitvoerbare bestand te laten inlezen en de symbolentabel te ontleden. De symbooltabel moet de naam van de functie bevatten, evenals het eerste instructieadres. Je zou dit adres dan in een functieaanwijzervariabele kunnen plaatsen en het kunnen aanroepen.

Ik denk dat ik kan proberen dit op te lossen.

EDIT: schrijf alsjeblieft nooit echte code zoals deze, maar hier is hoe je een functie kunt aanroepen met een string voor een Linux ELF binary met een intacte symbolentabel (libelf vereist):

#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;
  }   

4, Autoriteit 40%

#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");
}

5, Autoriteit 36%

Het is niet mogelijk in Pure C, maar je kunt misschien trucs spelen met DLL’s. Zet alle functies die u wilt selecteren in een DLL, gebruik vervolgens dlsym(of GetProcAddressON WINDOWEN, OF WAT andere API uw systeem biedt) om de functie aanwijzer te krijgen naam en bel met dat.

Dit werkt niet op sommige platforms, hetzij omdat ze helemaal geen dlellen hebben, of omdat als Symbian de functies in de DLL niet op runtime niet op nummertime toegankelijk zijn, alleen op nummer.

Houd er rekening mee dat als uw gebruiker u truct in het selecteren van een functie die niet de juiste parameters heeft voor de oproep die u wilt maken, dan gaat uw programma fout. C is echt niet ontworpen om dit soort dingen om te gaan.


6, Autoriteit 5%

Zoals gezegd door anderen, is het waar dat C geen reflectie-mechanisme heeft. Maar u kunt dit soort gedrag bereiken met behulp van dynamisch geladen bibliotheek / gedeeld object. In feite kunt u een dynamische bibliotheek laden en vervolgens kunt u de functies in de DLL / dus bellen met hun naam! Het is niet C en OS-specifieke maar dat is de weg. Het gebruikt DLOPEN op Linux en LoadLibrary op Windows. Je kunt bibliotheken vinden die het werk voor je doen zoals gtk / glib .


7, Autoriteit 5%

Is dit wat u probeert:

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;
}

8, Autoriteit 5%

Ik heb geprobeerd deze oplossing: naar het uitvoerbare openen als een dynamische bibliotheek met dlopen ()

.

Het werkt prima op mijn Linux Ubuntu, maar helaas niet op mijn ingesloten ARM doel. Ik weet niet waarom, als het afhangt van de glibc of de versie van libdl misschien.

Op mijn ARM doel, de boodschap is duidelijk:. “./Test8: kan niet dynamisch laden uitvoerbaar”

Hoe dan ook, de code die ik heb gebruikt is deze.

Ik gecompileerd met:

gcc test8.c -ldl -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;
}

9, Autoriteit 2%

Als ik uw vraag juist begrip u wilt laat gebruiken binden aan een C functie aan te roepen. Dat is niet iets wat je normaal kan doen in C. Symbolische namen (zoals namen van functies) worden niet opgeslagen in de code die wordt gegenereerd door de C-compiler. Je kan waarschijnlijk laten de compiler uitstoten symbolen, en vervolgens die te gebruiken om het einde van de uit te voeren bindend, maar de techniek zou variëren van compiler compiler en waarschijnlijk niet de moeite waard de hazzle.

Talen zoals C # en Java ondersteunt reflectie waardoor het gemakkelijk is te laat uit te voeren binden.


10

C arrays kunnen alleen worden geïndexeerd met integrale types. Dus schrijf een hash tabeltoewijzing snaren functie pointers.

Het is misschien ook de moeite waard te kijken naar de faciliteit in Python, Lua, andere scripttalen hun run-time insluiten in een C-programma. Delen van de C-code kan dan worden gemanipuleerd met de scripttaal

Alt’ly, sommige mensen code scripttaal extensies in C. Daarna kunnen ze de snelheid & amp hebben; lage niveau toegang van C in hun scripts.

Je zult vroeg of laat ontdekken dat het gebruik van dynamisch getypte idiomen in de scripttaal – zoals eval(), en de wazige lijn tussen functie en functienaam, en code die afhankelijk is van assoc-arrays – in C mogelijk is, maar uiteindelijk pijnlijk.


Antwoord 11

Introductie van de Nginx-c-functie.
Het is een NGINX-module waarmee u uw .so(c/c++)-toepassing in servercontext kunt koppelen en de functie van .so-toepassing kunt aanroepen in de locatierichtlijn. U kunt nginx share memory-gegevenscache implementeren via de nginx c-functie (https://github.com/Taymindis/nginx-c-function/wiki/Nginx-Cache-Data-via-nginx-c-function).
Dit is voor ontwikkelaars die graag c-server hosten.
https://github.com/Taymindis/nginx-c-function

Other episodes