views:

1171

answers:

10

Hello everybody,

I want to call a function using a variable.Is it possible in C?? Actually, what I want to do is, get the function name from the user and store it in a variable say var. Now I want to call the function that has its name stored in the variable var. Can anyone tell me how this can be done in C?

Actually I want to develop an AI game engine for a two player game. Two programs with no main function that implement the logic for winning the game will be fed to the game engine. Let me be clear that the program names will be same as that of the primefunctions in the program that implement the logic for winning the game.

So when the user enters the name of first and second players, I can store them in 2 different variables. Now, since the primefunction names are same as that of the program names, I intend to call the functions with variables containing the prog names. Can u help me do this in C?

+18  A: 

C does not support this kind of operation (languages that have reflection would). The best you're going to be able to do is to create a lookup table from function names to function pointers and use that to figure out what function to call. Or you could use a switch statement.

Blair Conrad
Yeah there's no built in feature to do this but you could make one yourself.
Jonas
Had the exact same answer :P
Amadeus45
Same answer from me. Would be an interesting exercise to do though...
zebrabox
Same answer as well, but I had code so I decided to leave it.
GMan
+1  A: 

If I understand your question correctly you want to use late binding to call a C function. That is not something your normally can do in C. Symbolic names (like names of functions) are not stored in the code generated by the C compiler. You could probably let the compiler emit symbols, and then use those to perform the late binding, but the technique would vary from compiler to compiler and probably not be worth the hazzle.

Languages like C# and Java supports reflection making it easy to perform late binding.

Martin Liversage
+12  A: 

The best you can do is something like this:

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

This uses numbers instead of strings to identify the functions, but doing it with strings is simply a matter of converting the string into the proper function.

What are you doing, exactly? If just for curiosity, here you go, but if you're trying to solve a problem with this, I'm sure there is a way better suited to your task.

Edit

In concern with your edit, you will want to go with onebyone's answer, for sure.

You want your user's to build dynamic libraries (thats a shared object [.so] in Linux, and a dynamic link library [.dll] in Windows).

Once you do that, if they provide you with the name of their library, you can ask the operating system to load that library for you, and request a pointer to a function within that library.

GMan
+1 for "if you're trying to solve a problem with this, I'm sure there is a way better suited to your task."
therefromhere
+1 for memtion the dynamic libraries to solve the problem.
kingkai
+1  A: 

This might interest you : http://www.newty.de/fpt/index.html (google function pointer).

Aif
+6  A: 

It's not possible in pure C, however you may be able to play tricks with dlls. Put all the functions you want to select from into a dll, then use dlsym (or GetProcAddress on Windows, or whatever other API your system offers) to get the function pointer by name, and call using that.

This doesn't work on some platforms, either because they don't have dlls at all, or because like Symbian the functions in the dll can't be accessed by name at runtime, only by number.

Be aware that if your user tricks you into selecting a function which doesn't have the right parameters for the call you want to make, then your program will go wrong. C really isn't designed to cope with this kind of thing.

Steve Jessop
Or whichever dynamic library API is available on your OS. :)
GMan
As a side note; if you want to access functions using `dlsym`, they don't actually have to be in a dll; you can link your executable in a suitable fashion and treat the executable image as a dll for this purpose.
Williham Totland
@GMan: added. Stupid non-POSIX systems ;-). @William: sounds good, does calling dlopen(0, mode) achieve this?
Steve Jessop
onebyone, yes, that's what `dlopen(NULL,` achieves (you also have to tell the linker you want your symbols available to the dynamic loader, using `-rdynamic` with gcc).
caf
+1  A: 

As said by others, it is true that C has no reflection mechanism. But you can achieve this sort of behaviour by using dynamic loaded library/shared object. In fact you can load a dynamic library and then you can call the functions in the dll/so with their name ! It is not C and OS specific but that's the way. It use dlopen on Linux and LoadLibrary on windows. You can find libraries that do the work for you like gtk/glib.

neuro
+1  A: 

Is this what you are trying:

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;
}
Naveen
+5  A: 

While this isn't exactly a practical solution, I bet you could certainly call a function by a string by having a program read in it's own executable and parse the symbols table. The symbol table should contain the name of the function as well as it's first instruction address. You could then place this address in a function pointer variable and call it.

I think I may try and whip this up.

EDIT: Please no one ever write real code like this, but here is how you can call a function using a string for a Linux ELF binary with an intact symbols table (requires 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();
    return 0;
  }
Falaina
i love this idea
p4bl0
Of, course, i should have think of it :-)+1 for the idea.
neuro
You could also dlopen(0, ...) and dlsym(symbol) instead of looping.
Bryan Drewery
A: 

C arrays can only be indexed with integral types. So write a hash table mapping strings to function pointers.

It might also be worth looking at the facility in Python, Lua, other script languages to embed their run-time in a C program: parts of the C code can then be manipulated with the scripting language.

Alt'ly, some people code script language extensions in C. Then they can have the speed & low level access of C in their scripts.

You are going to find, sooner or later, that using dynamically typed script language idioms - like eval(), and the blurry line between function and function name, and code that depends on assoc arrays - in C is possible but ultimately painful.

+2  A: 
#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