Call a function named in a string variable in C

I want to call a function using a variable. Is this possible in C?

Actually, I want to get the function name from the user and save it in a variable. Now I want to call the function whose name is saved. Can someone tell me how to do this in C?

I want to develop an AI game engine for a dual-player game. Two programs without the main function that implement the logic of winning the game will be transferred to the game engine. Let me make it clear that the names of the programs will be the same as in simple functions in the program that implement the logic of winning the game.

So, when the user enters the name of the first and second players, I can store them in two different variables. Now, since the names of the prime functions are the same as the names of the programs, I intend to call functions with variables containing the names of the prog.

+50
c function
Jul 13 '09 at 10:26
source share
13 answers

C does not support such an operation (languages ​​in which there is reflection). The best you can do is create a lookup table from function names to function pointers and use it to determine which function to call. Or you can use the switch statement.

+41
Jul 13 '09 at 10:29
source share
β€” -

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 functions, but doing it with strings is just converting the string to the correct function.

What do you do? If only for the sake of curiosity, here you go, but if you are trying to solve the problem with this, I am sure there is a way that is better suited to your task.

Edit

In connection with your editing, you probably want to answer with onebyone's answer.

You want your user to create dynamic libraries (that is, a shared object [.so] on Linux and a dynamic link library [.dll] on Windows).

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

+36
Jul 13 '09 at 10:33
source share

Although this is not quite a practical solution, I bet you could, of course, call the function line by line if the program read its own executable file in it and analyzed the symbol table. The symbol table must contain the name of the function, as well as the address of the first instruction. Then you can put this address in the function pointer variable and call it.

I think I can try to hack this.

EDIT: Please, no one ever wrote real code like this, but here is how you can call a function using the line for Linux ELF binary file with a table of intact characters (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 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 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; } 
+27
Jul 13 '09 at 10:53
source share

This is not possible in pure C, however you can play tricks with dll. Put all the functions you want to select in the dll, then use dlsym (or GetProcAddress on Windows or any other API that your system offers) to get a pointer to the function by name and call it using this.

This does not work on some platforms either because they do not have libraries at all, or because, like Symbian, functions in the dll cannot be accessed by name at run time, only by number.

Keep in mind that if your user tricks you into choosing a function that does not have the right parameters for the call you want to make, your program will go wrong. C is really not designed to handle such things.

+15
Jul 13 '09 at 10:36
source share
 #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"); } 
+12
Jul 13 '09 at 17:11
source share

As others say, it is true that C does not have a reflection mechanism. But you can achieve this behavior using a dynamically loadable library / shared object. In fact, you can load a dynamic library, and then you can call functions in dll / so with their name! This is not C and OS, but a way. It uses dlopen for Linux and LoadLibrary for Windows. You can find libraries that do the work for you, for example .

+2
Jul 13 '09 at 10:42
source share

This is 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; } 
+2
Jul 13 '09 at 10:48
source share

If I understand your question correctly, you want to use the last binding to call function C. This is not what you can usually do in C. Character names (like function names) are not stored in the code generated by the C compiler. Probably you can let the compiler emit characters and then use them to do late bindings, but the technique will be different from compiler to compiler and probably not worth the gas.

Languages ​​like C # and Java support reflection, making late binding easier.

+1
Jul 13 '09 at 10:32
source share

I just tried Steve Jessop's approach using the statically linked library suggested by Williham Totland in the comments and it turned out to be non-trivial.

First, you will find many places on the Internet (including Wikipedia) that tell you that the way to open the main program as a library is to call dlopen (3), like this dlopen(NULL, 0) . This will not work for glibc because the binding flag must be specified, as the man page clearly states:

The flag must include one of the following two values:
RTLD_LAZY
Perform lazy binding. Only allow characters as code ...
RTLD_NOW
If this value is specified or an environment variable ...

I don’t think you are choosing questions here because you are going to link all the symbols from the static library to your executable.

This leads us to the following problem. The component will not include characters from your static library in your executable file because they are not referenced . The way to force the GNU linker to include characters in any case is -Wl,--whole-archive path/to/static/lib.a -Wl,--no-whole-archive , as this answer describes. The way to force the Mac OS X linker to include all the characters from your static library is -Wl,-force_load path/to/static/lib.a

+1
Nov 02 '16 at 6:38
source share

C arrays can only be indexed with integral types. Therefore, write the hash table display strings for function pointers.

It is also possible to look at an object in Python, Lua, and other scripts to embed their run-time into a C program: parts of the C code can then be processed using a scripting language.

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

You will sooner or later find that using dynamically typed script language words such as eval () and a blurry line between the name of a function and function and code that depends on arrays of dependencies - in C, is possible but ultimately painful.

0
Jul 13 '09 at 16:52
source share

Introducing the Nginx-c function. This is the NGINX module that allows you to link your .so application (c / c ++) in the server context and call the .so application function in the location directive. You can embed the nginx shared memory data cache through the nginx c function ( https://github.com/Taymindis/nginx-c-function/wiki/Nginx-Cache-Data-via-nginx-c-function ). This is for developers who like hosting with a server. https://github.com/Taymindis/nginx-c-function

enter image description here

0
Sep 30 '17 at 6:50
source share

I tried this solution: the idea is to open the executable as a dynamic library using dlopen () ...

Unfortunately, this does not work everywhere. I don't know if this depends on glibc or the libdl version?

For example, on Linux Ubuntu, this is normal. Then, after compiling and trying to target, I got a nice message "./test8: cannot load dynamically executable file".

Anyway, the code I used is this.

I compiled with:

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; unsigned char *function_name = "TEST_MyTestFunction"; 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; } 
0
Apr 04 '19 at 8:02
source share

Compiling as a dynamic library and using dlsym() can help. At least this is the only way I know, but it does not support cxx.

-one
Nov 30 '17 at 17:34
source share



All Articles