1

I have a little bit unusual question. Let's imagine i have N amount of functions:

void function1(){ //some code here }
void function2(){ //some code here }
...
void functionN(){ //some code here }

Is there any way, I could compute or find out dynamically, which function to use, without IF statements? And depending on the name of function name, call it? Let me show you pseudocode, that can better describe situation:

 for(int I=1;I<=N;I++){
    functionI();
 }

I mean, if is it somehow possible to compute (in a char array for example, but also by any other way) kind of code, which I will insert and use later. But not as string, but directly like a code. Let me demonstrate on different example:

int num=3;
char functionInString[]="printf(num);
//Some code, that would for example change letters in 
functionInString, for example to different fuction 
consisting of letters

//And here, do whatever is written in functionToString

Sorry if I was not clear enough. Can anyone tell me, if is it possible in C, or any different language, and how is this concept called?

victory
  • 185
  • 1
  • 2
  • 16
  • 2
    Possible duplicate of [How do function pointers in C work?](https://stackoverflow.com/questions/840501/how-do-function-pointers-in-c-work) –  Nov 30 '18 at 01:47
  • 2
    Generally, it's called ['dynamic dispatching'](https://en.wikipedia.org/wiki/Dynamic_dispatch) or [strategy pattern](https://en.wikipedia.org/wiki/Strategy_pattern) in OO. You can implement it with plain switch-case or [function pointers](https://lwn.net/Articles/444910/) in C. – snipsnipsnip Nov 30 '18 at 01:57
  • 1
    You might want to use some scripting language that has `eval` functionality. – Lorinczy Zsigmond Nov 30 '18 at 12:24

3 Answers3

5

You may need to understand what closures and callbacks are. Function pointers are useful, but might not be enough alone (read more to understand how function pointers are useful to implement closures).

You should learn more about C, so read good books about C programming. I recommend downloading the C11 standard n1570 and glancing into it. A very important notion is undefined behavior and you should be scared of it.

if is it somehow possible to compute (in a char array for example, but also by any other way) kind of code, which I will insert and use later. But not as string, but directly like a code.

This is not possible in purely standard C code (since the set of translation units comprising your program is fixed), and in principle any valid function pointer value should point to some existing function (so stricto sensu calling any other function pointer value would be undefined behavior). However, some implementations are able to construct (in some implementation specific way), somehow "valid" new function pointers (but that is outside of the C11 standard). On purely Harvard architectures with code sitting in ROM, that is not even possible.

generating and dynamically loading plugins

However, if you are running under a modern operating system (I recommend Linux) you might use dynamic loading and plugin facilities. I am focusing on Linux specifically (for Windows, details are very different, and the evil is in the details; read Levine's book Linkers and Loaders). Read Operating Systems: Three Easy Pieces to learn more about OSes.

So what you could do (on Linux) is to generate at runtime some C code in some temporary file, such as /tmp/generated.c; you need to define your conventions about that file (e.g. that it defines a void pluginfun(int) function having some additional desirable properties); then you fork a compilation command to compile that into a shared object (read How to write shared libraries by Drepper), that is a plugin. So your program might run (perhaps using system(3), or lower level system calls like fork(2), execve(2), waitpid(2) etc....) a compilation process like e.g. gcc -Wall -O -fPIC /tmp/generated.c -shared -o /tmp/generatedplugin.so; later, your main program would load that plugin using dlopen(3) :

void* dlh = dlopen("/tmp/generatedplugin.so", RTLD_NOW);
if (!dlh) { 
  fprintf(stderr, "dlopen /tmp/generatedplugin.so failed: %s\n",
          dlerror());
  exit(EXIT_FAILURE);
}

Since you care about function pointers, your code would be more readable if you declare their signature as a type:

typedef void pluginfun_type(int);

Then a function pointer to functions of that signature is easily declared:

pluginfun_type* fptr = NULL; 

and your program can get with dlsym(3) the pluginfun function address in your plugin:

fptr = (pluginfun_type*) dlsym(dlh, "pluginfun");
if (!fptr) {
   fprintf(stderr, "dlsym of pluginfun failed: %s\n", dlerror());
   exit(EXIT_FAILURE);
}

and at last use (*fptr)(3) to call that function.

You should use gcc -O -Wall foo.o bar.o -rdynamic -ldl -o foobarprog to link your main program. You might call at last dlclose(3) but you should not do that if you have some call frame still active for a function inside your plugin.

Such a generating plugin approach works extremely well on Linux. My manydl.c is a toy program generating "random" C code, forking a compilation of that generated C code into a generated plugin, and loading that plugin (and can repeat that many times). It shows that in practice, a Linux program can generate and load many hundred thousands (and perhaps even millions, if you are patient enough) plugins. The code segments leak is in practice acceptable (and might be avoided by careful use of dlclose)

And computer are quite fast today. You might generate a small plugin (of less than a thousand lines of C) on every REPL interaction, and compile it and load it (for such a small plugin, it usually takes less than 0.1 second), and that is practically compatible with human interaction (I did so in my obsolete GCC MELT project; and I will do so in my bismon project described in the bismon-chariot-doc.pdf draft report).


using a JIT-compiling library

To generate code dynamically at runtime, you might also use some JIT-compilation library. There are many of them, including libgccjit, LLVM (in C++), asmjit, libjit, GNU lightning, tinycc with its libtcc. Some of them are able to emit machine code quickly, but then the performance of that code might not be very good. Other are doing optimizations like a good C compiler (in particular libgccjit which uses GCC inside). Of course, these optimizations take some time, so the machine code is emitted much slowly but its performance is as good as optimized C code.


Embedding an interpreter

In many cases, scripting languages offer some kind of eval. Several interpreters are designed to be easily embeddable in your application (with cautions and caveats), notably Lua or Guile (and Nim). Many more interpreters (Ocaml, Python, Perl, Parrot, Ruby, ...) can somehow be embedded in your application also (you may need to understand garbage collection terminology). Of course all require some coding conventions. And interpreters are in practice slower than compiled code.


Terminology

Can anyone tell me, if is it possible in C, or any different language, and how is this concept called?

You probably need to read more about metaprogramming, eval, multistage programming, homoiconicity, reflection, continuations, type introspection, stack trace (consider Ian Taylor's libbacktrace).

You may be interested by Lisp-like languages. Read first SICP, then Queinnec's book Lisp In Small Pieces and Scott's book Programming Language Pragmatics. Notice that SBCL (a Common Lisp implementation) is generating machine code at every REPL interaction.

Since you mention an interest in artificial intelligence, you could look into J.Pitrat's blog. His CAIA system is bootstrapped so generating the totality of its C code (in nearly 500KLOC).

Basile Starynkevitch
  • 223,805
  • 18
  • 296
  • 547
  • What makes you think the OP is programming a Linux PC? This might as well be some other OS or a microcontroller, for all we know. – Lundin Nov 30 '18 at 09:24
  • Nothing, except my personal recommendation. As I wrote, plugins are not in the C11 standard and usually require some extra library – Basile Starynkevitch Nov 30 '18 at 09:25
4

Try to work with function pointer arrays;

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

void myfunc1(){printf("1\n");};
void myfunc2(){printf("2\n");};
void myfunc3(){printf("3\n");};
void myfunc4(){printf("4\n");};
void myfunc5(){printf("5\n");};

void (*myfuncs[5])() = {myfunc1, myfunc2, myfunc3, myfunc4, myfunc5};

int main(int argc, char *argv[])
{
    for(int i=0;i<5;i++) {
            (myfuncs[i])();
    }
    exit(EXIT_SUCCESS);
}
Hoppo
  • 41
  • 1
  • 2
4

Use an array of function pointers. First define the format:

typedef void func_t (void);

Then create an array of function pointers:

func_t* func[n] = {function1, function2, function3};

Example:

#include <stdio.h>

void function1 (void) { puts(__func__); }
void function2 (void) { puts(__func__); }
void function3 (void) { puts(__func__); }

typedef void func_t (void);

#define n 3

int main()
{
  func_t* func[n] = {function1, function2, function3};
  for(size_t i=0; i<n; i++)
  {
    func[i]();
  }
}
Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 1
    nearly the same answer as [Hoppo's one](https://stackoverflow.com/a/53553680/841108), an hour earlier – Basile Starynkevitch Nov 30 '18 at 09:18
  • @BasileStarynkevitch Yes but I dislike hiding pointers behind typedef even in case of function pointers. This is more readable and in line with the rest of the C language syntax. – Lundin Nov 30 '18 at 09:19