call_user_func() ähnliche Funktion

lolilol

Mitglied
Hallo,

ich brauch für einen Simulator viele Funktionsaufruf (genaugenommen für jeden Befehl eine). Über switch() liese sich das zwar realisieren, würde jedoch seehr lang werden.

Jetzt habe ich (für C) nach einer Funktion gesucht, die ähnlich wie die PHP-Funktion call_user_func(func_name, arg1, arg2, etc.) arebitet, die Funktionen also anhand des Namens aufgerufen werden können. Hat hier jemand eine Idee? Oder ist das unter C garnicht möglich?

Gruß
loli
 
Hi.

Sowas ist in C nicht möglich. Und mit einer switch Anweisung kannst du nur integrale Typen verarbeiten - keine Strings.

Gruß
 
Hallo,

die Funktion call_user_func() bildet wohl so eine Art Reflection Mechanismus ab. Das geht in C nicht.
Sprich man kann keine Funktion direkt anhand eines Strings aufrufen...
Eine elegeante Moeglichkeit in C++ waere die Abbildung
String-> Funktionzeiger ueber die Datenstruktur map...
Allerdings geht das wie gesagt 1. nur in C++ und 2. muesste man diese map erstmal fuellen...

Eine Bibliotheksfunktion die einen Funktionsnamen anhand eines Strings aufloest kenne ich nicht...

@switch siehe deepthroat

Gruß,

RedWing
 
Wenn ich Dich richtig verstanden habe, möchtest Du C-Funktionen dynamisch aufrufen, d.h. der Anwender gibt den Namen der Funktion und deren Parameter ein und Dein Programm führt diese Funktion aus.
Das wird aus folgenden Gründen nicht funktionieren:
1. In C sind die Funktionsnamen nur Platzhalter für die Adressen der Funktionen und existieren im kompilierten Programm nicht mehr (es gibt auch Ausnahmen, z.B. Debug-Angaben, da ist die Symboltabelle mit drin).
2. Im fertig kompilierten Programm existieren nur die Funktionen, die auch tatsächlich aufgerufen werden.
3. switch: siehe deepthroat

Du müßtest für jede Funktion, die Du unterstützen willst, einen if-Zweig in der Art
Code:
if(strcmp(funcname, "sin") == 0)
{
    double Parameter1;
    //Parameter extrahieren (Fehlerbrehandlung nicht vergessen!)
    ...
    //Funktion aufrufen
    result = sin(Parameter1);
    //Ergebnis ausgeben
    printf("Ergebnis von %s = %f", funcname, result);
}
Das wäre aber ziemlich aufwändig. Was willst Du denn bezwecken?

P.S. in PHP geht das, weil PHP (afaik) eine Skriptsprache ist. Der PHP-Code wird nicht kompiliert und dann als EXE ausgeführt, sondern zur Laufzeit interpretiert. Alle PHP-Funktionen sind also zur Laufzeit und mit Namen vorhanden, da sie ja vom Interpreter aufgerufen werden müssen.

EDIT:
@RedWing: das geht auch mit C. Du erstellst einen struct 'map':
Code:
typedef struct MAP
{
    char* name;
    void* func_ptr;
}map;
Dann definierst Du noch einen Listen-struct dafür und schreibst Dir die Funktionen zum Einfügen, Löschen und suchen. Da ist aber der Aufwand auch etwas hoch und Du mußt immer noch berücksichtigen, daß unterschiedliche C-Funktionen unterschiedliche Anzahlen und Typen von Parametern haben. Ich könnte mir schon vorstellen, wie man das alles auch in die 'map'-struct einbauen könnte, das würde jetzt aber hier, glaube ich, etwas zu weit führen.
 
Zuletzt bearbeitet:
@RedWing: das geht auch mit C. Du erstellst einen struct 'map':

Ja das schon, aber mit erheblich mehr Aufwand, als die Implementierung einer if Kaskade...
Mit "nicht gehen" meinte ich, das es dafuer keine Bibliothek gibt.

//edit: btw eine stl map ist als ausgeglichener Baum implementiert um die Suche nach Elementen zu optimieren. Viel Spass wenn du
das selber in C abbilden willst :)

Gruß,

RedWing
 
Zuletzt bearbeitet:
Naja, man könnte es am einfachsten vielleicht noch mit einem Array machen:
C:
typedef struct _cmd {
  char *name;
  void (*function) (void*);
} cmd;

#define MAP_FUNCNAME(name)  { #name, func_ ## name }

cmd commands[] = { 
  MAP_FUNCNAME(print),
  MAP_FUNCNAME(run),
  { NULL, NULL }
};

#undef MAP_FUNCNAME

void func_print(void* args) {
}

void func_run(void* args){
}

So kann man dann eine Funktion schreiben, die anhand eines übergebenen Strings aus der Befehlsliste die entsprechende Funktion heraussucht und mit den Parametern die man als Zeiger übergeben kann aufruft. Die Parameter sollten ja eigentlich auch nur eine Liste von Strings sein, oder?

Gruß
 
deepthroat hat gesagt.:
Naja, man könnte es am einfachsten vielleicht noch mit einem Array machen:

Auch da muesste man das Array erstmal durchlaufen und ueberpruefen ob der Name enthalten ist.
Sollte rein vom schreibaufwand her das selbe sein... Allerdings waere das schoener anzuschauen :)

jokey2 hat gesagt.:
2. Im fertig kompilierten Programm existieren nur die Funktionen, die auch tatsächlich aufgerufen werden.

Da haette ich noch etwas einzuwenden :)

Code:
int add(){
}

int main (){
}

jetzt hab ich das Programm uebersetzt und im Binary nach dem Wort "add" gesucht und einen Treffer erhalten.
Also scheint die These nicht ganz zu stimmen...

Gruß,

RedWing
 
Mhh.. das hatte ich fast befürchtet :/

Hab mich jetzt einfach für die einfachste Lösung entschieden:

Code:
if(strcmp(name, "name")) name();
else if(strcmp(name, "name")) name();
else if(strcmp(name, "name")) name();
else if(strcmp(name, "name")) name();
else ... // *heul*

Hässlich, aber der geringste Aufwand, vorallem da sich gezeigt hat, dass viele Assemblerbefehle vom Op-Code her gleich sind und so zusammengefasst werden können. Sind nur ca. 40-50 übriggeblieben und somit der Aufwand von deepthroat Idee dem ganzen nicht gerecht werden würde.

Gruß und danke an alle,
loli
 
jetzt hab ich das Programm uebersetzt und im Binary nach dem Wort "add" gesucht und einen Treffer erhalten.
Also scheint die These nicht ganz zu stimmen...
Es ist möglich, daß das vom verwendeten Linker und den Optimierungseinstellungen abhängt. Ein optimierter Maschinencode sollte keine Funktionen enthalten, die nicht aufgerufen werden. Wenn der Funktionsname im Code steht, dann in der Symboltabelle (beim ELF-Format) oder dem Äquivalent bei EXE's. Die ist nur für Debuggingzwecke nötig. Ein Programm ohne Debug-Informationen enthält nur die Namen von Funktionen, die aus einer dynamisch gelinkten Bibliothek aufgerufen werden.
 
jokey2 hat gesagt.:
Es ist möglich, daß das vom verwendeten Linker und den Optimierungseinstellungen abhängt. Ein optimierter Maschinencode sollte keine Funktionen enthalten, die nicht aufgerufen werden. Wenn der Funktionsname im Code steht, dann in der Symboltabelle (beim ELF-Format) oder dem Äquivalent bei EXE's. Die ist nur für Debuggingzwecke nötig. Ein Programm ohne Debug-Informationen enthält nur die Namen von Funktionen, die aus einer dynamisch gelinkten Bibliothek aufgerufen werden

An das habe ich nat. gedacht. Ich habe das Programm mit allen 3
Optimierungsstufen die der gcc besitzt kompiliert und den Debugschalter
ohnehin nicht verwendet, trotzdem war das Symbol add im Binary enthalten...

Gruß,

RedWing
 
Zurück