Archiv verlassen und diese Seite im Standarddesign anzeigen : Pointer auf Funktionen mit verschiedenen Parametern
Hallo Leute, ich hätte da mal eine Frage...
angenommen ich hätte eine Liste mit Pointern auf unterschiedlichste Funktionen, wobei zusätzlich noch Informationen über die jeweilige Anzahl an Parametern (und ggf. deren Typen) vorhanden ist. Und jetzt möchte ich gerne eine dieser Funktionen ausführen, wobei die Parameter wiederum in irgendeiner anderen Liste stehen.
Ich stelle mir das etwa so vor:
typedef struct
{
void* pFunc;
char* name;
uint8_t num_args;
} type_func;
type_func Funclist[] =
{
{fptr1, "Funktion_1", 0},
{fptr2, "Funktion_2", 3},
{fptr3, "Funktion_3", 1},
etc, etc, etc...
};
int8_t execute_function(type_func* pFunction, void* args)
{
???
}
falls ich Funktion_2 ausführen möchte würde ich execute_function also das entsprechende Element meiner Funktionsliste übergeben, sowie die zu verwendenden Parameter (die wiederum in einer verketteten Liste gespeichert sein könnten, oder sonst irgendwie).
Ziel der Aktion: ich möchte auf der Konsole "Funktion_2(1, 2, 3) <Enter>" eingeben können, woraufhin ein Parser zunächst den eingegebenen Text als Funktionsaufruf erkennt, die Parameter extrahiert, und schließlich die zugehörige Funktion mit den passenden Parametern aufruft.
Das muss doch irgendwie machbar sein...
stdarg.h spukt mir dazu im Kopf rum, aber ich bin nicht sicher ob und wie ich das für mein Problem nutzen kann.
Was meint ihr dazu?
Keine Ideen?
Also ich bin inzwischen davon überzeugt, daß sich stdarg.h (leider) nicht zur Lösung meines Problems nutzen lässt...
Daher verfolge ich jetzt einen anderen Ansatz:
Die Funktion "execute_function" wird in Assembler implementiert und sichert natürlich erstmal alle relevanten Register. Anschließend wird die Parameterliste abgearbeitet, und jeder Parameter im passenden Register bzw. auf dem Stack abgelegt (siehe avr-libc FAQ: function call conventions). Prinzipiell muss die Funktion dann nurnoch per Call aufgerufen, und hinterher wieder aufgeräumt werden (Register wiederherstellen).
Das sollte es mir schonmal ermöglichen, beliebige Funktionen mit beliebigen Parametern korrekt auszuführen. Dann würde nurnoch der Rückgabewert der Funktion fehlen, aber den auch noch zu berücksichtigen dürfte - wenn der Rest funktioniert - ziemlich trivial sein.
Hallo Felix,
bist du sicher, dass du in C dazu Assembler brauchst?
In Object Pascal verwende ich einfach den Namen des Parameters, der den Verweis auf die Procedur enthält zum Aufrufen dieser Procedur. Register und Stack bedient der Compiler, da brauche ich mich nicht drum zu kümmern.
Beispiel:
Der Parameter rechne enthält einmal den Funktionsnamen addiere und einmal den Funktionsnamen multipliziere, dann rufe ich auf:
z:=rechne(x,y);
Das wars dann auch schon.
grüsse,
Hannes
Ich fürchte in C geht das nicht so einfach...
das beste was mir da zur Verfügung steht sind Funktionspointer, bei denen dem Compiler aber Typ und Anzahl der Parameter bekannt sein müssen. Außerdem bietet C noch ein Werkzeug zum Umgang mit einer variablen Anzahl an Parametern, aber dann müssen die Funktionen die ich aufrufen möchte auch darauf ausgelegt sein (ich möchte aber jede beliebige Funktion aufrufen können).
stdarg ist für so was ähnliches gedacht, es wird zb. für funktionen wie
int printf(const char *format, ...);
verwendet, das "..." ist kein auslassungszeichen, sondern valide C-syntax, eben für "variable argumente".
dh du mußt, um die variablen argumente abzuarbeiten, mit va_start, va_arg, va_end hantieren, und du müßtest einen weg finden, die variablen argumente aus deiner aufrufenden funktion wiederum varargs-mäßig verpacken, da fällt mir jetzt kein standard-weg ein dafür.
wie wärs mit einer anderen lösung, du übergibst die argumente einfach als array oder verkettete liste:
struct arglist {
int value;
struct arglist *next;
};
void func_add(struct arglist *args) {
int result = 0;
for(; arglist; arglist = arglist->next)
result += arglist->value;
// irgendwas mit result machen
}
void main(void) {
struct arglist a1, a2, a3;
a1.value = 1;
a1.next = a2;
a2.value = 2;
a2.next = a3;
a3.value = 3;
a3.next = NULL;
func_add(&a1);
}
(natürlich ungetestet).
du mußt ja bei deinem parser sowieso die argumente in irgendwelchen datenstrukturen unterbringen, dann kannst du das gleich so designen, daß es zusammenpasst.
HTH,
cm.
Klar, sowas geht...
aber nur für Funktionen die eben auch "dafür vorgesehen" sind. Zusätzlich möchte ich aber auch jede beliebige andere Funktion aufrufen können, und das geht in C dann leider nicht mehr.
aber nur für Funktionen die eben auch "dafür vorgesehen" sind. Zusätzlich möchte ich aber auch jede beliebige andere Funktion aufrufen können, und das geht in C dann leider nicht mehr.
man kann halt nicht alles haben :-)
was noch ginge, wäre sowas:
switch (functype) {
case NOARGS:
funcp(); break;
case ONE_INT:
funcp(int1); break;
case TWO_INTS:
funcp(int1, int2); break;
[...]
case TWO_INTS_ONE_CHAR_ONE_VOIDP:
funcp(int1, int2, char1, voidp1); break;
}
sprich, für jede kombination von argument-typen ein case im switch. vermutlich mußt du dazu auch den funcp noch entsprechend casten, damit der compiler mitkriegt, was er auf den stack werfen muß...
nein, schön ist das nicht.
cm.
Hallo Felix,
wenns nur darum ginge, eine begrenzte Anzahl von Parameterkonstellationen zu verarbeiten, könnte man das durch Überladen von Procedurdefinitionen lösen.
Aber anscheinend willst du das so hinkriegen, dass JEDE BELIEBIGE Parameterkonstellation verarbeitet wird. Da wird dir die Verwendung von Assemblerbefehlen wohl nicht erpart bleiben.
grüsse,
Hannes
Aber anscheinend willst du das so hinkriegen, dass JEDE BELIEBIGE Parameterkonstellation verarbeitet wird. Da wird dir die Verwendung von Assemblerbefehlen wohl nicht erpart bleiben.exakt...
aber das sollte schon klappen, da der AVR-GCC gut dokumentiert ist.
Die ersten Parameter kommen in R25 bis R8 (aber immer nur gerade Register, d.h. wäre der erste Parameter ein uint8_t käme er in R24, ein uint16_t würde in R24 und R25 landen). Und alles was sich nicht in diesen Registern unterbringen lässt kommt auf den Stack.
Ich muss mir für den AVR nurnoch etwas umfassendere ASM-Kenntnisse aneignen, da kocht ja leider jeder Hersteller bei jeder µC-Reihe sein eigenes Süppchen.
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.