Nabend
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
An letzter Stelle von dieser Struktur kann Ich ein Funktion zuweisen. Was macht man wenn man zig verschiedene Funktionen hat, mit verschiedenen Parametern? Gibt es einen Trick oder brauche ich dafür wieder eine spez. Struktur?
|
Anzeige
|
Funktionspointer in einer StrukturNabend
An letzter Stelle von dieser Struktur kann Ich ein Funktion zuweisen. Was macht man wenn man zig verschiedene Funktionen hat, mit verschiedenen Parametern? Gibt es einen Trick oder brauche ich dafür wieder eine spez. Struktur? Hm. Pointer auf void und eine struktur uebergeben auf die gecasted wird? Keine Ahnung ob das UB ist.
Gast
#5292610
Union aller benötigen FP. Jan H. schrieb: > Was macht man wenn man zig verschiedene Funktionen hat, mit > verschiedenen Parametern? > Gibt es einen Trick oder brauche ich dafür wieder eine spez. Struktur? Was willst Du damit machen? Willst Du diese unterschiedlichen Funktionen über ein und denselben Pointer aufrufen können? Das kann nicht funktionieren, wie willst Du den Funktionen die unterschiedlchen Parameter übergeben? Du brauchst schon einen zur jeweiligen Funktionssignatur passenden Funktionspointer. Oder Du musst alle Funktionen mit variabler Parameterliste anlegen und als ersten festen Parameter eine Kennung mitliefern, wie die variable Parameterliste zu interpretieren ist. Bist Du Dir sicher, daß das das ist, was Du willst? Achim S. schrieb: > Union aller benötigen FP. Pseudo Code, wie soll das gehen? > Bist Du Dir sicher, daß das das ist, was Du willst?
Ich möchte eine Art LCD Struktur anlegen. Nicht jede Funktion hat die
gleiche Anzahl an Parameter und Typ.
Daher müsste Ich verschiedene Parameter übergeben.
Für verschiedene Funktionen solltest du verschiedene Funktionszeiger anlegen. Soweit, so offensichtlich. Wenn die Funktionen aber das gleiche tun sollen, weil du eine Abstraktion baust, dann machst du mit "die brauchen unterschiedliche Parameter und Typen" was falsch, denn dann ist das keine ordentliche Abstraktion. Du kannst deine 30 verschiedenen Funktionen (mit verschiedenen Namen) aber in einer Union vereinigen und dann die Union in deine Struktur einbinden. Musst natürlich dann immer durch den korrekten Zeiger aufrufen, sonst passiert Murks. S. R. schrieb: > Du kannst deine 30 verschiedenen Funktionen (mit verschiedenen Namen) > aber in einer Union vereinigen und dann die Union in deine Struktur > einbinden. Musst natürlich dann immer durch den korrekten Zeiger > aufrufen, sonst passiert Murks. Hast du ein Pseudo Kode für mich?
Gast
#5292675
Code hat Achim schon geschrieben, danke. Aber erkläre mal lieber, was du eigentlich vorhast? "LCD Struktur" ist erstmal nichtssagend, und deine Frage klingt eher danach, als ob du groben Unfug treiben willst, ohne es zu wissen. Da gibt es bestimmt bessere Ansätze. Aus dem Struct muss der Zeiger dann komplett raus?
Mit so wenig Information schwer zu sagen, ob das hier vernünftig wäre, aber deiner Beschreibung nach könntest Du die Funktionen auch variadisch implementieren. Sie hätten dann für den Compiler allesamt dieselbe Parameterliste und die Frage nach der Union stellt sich nicht. Markus F. schrieb: > Mit so wenig Information schwer zu sagen, ob das hier vernünftig wäre, > aber deiner Beschreibung nach könntest Du die Funktionen auch variadisch > implementieren. Wie stellt man das an? Frage waere ja noch von wem diese Funktionen aufgerufen werden, und wie dieser denn uwberhaupt die Paramerer kennt. Kannst Du vielleicht mal Beispielr fuer die unterschiedluchen Funktionen geben? Dumdi D. schrieb: > Frage waere ja noch von wem diese Funktionen aufgerufen werden, > und wie > dieser denn uwberhaupt die Paramerer kennt. Kannst Du vielleicht mal > Beispielr fuer die unterschiedluchen Funktionen geben?
Jan H. schrieb: > void handle7SEGMENT(void) > void led_show_temp(int16_t tempIn, uint8_t sense) > uint8_t *i2c_scan(uint8_t *buffer) Ok. Und woher soll die aufrufende Funktion wissen welche Daten sie da reinschreiben soll? D.h. Du musst sowieso ajtiv Fallunterscheidungej machen. Oder wrapper Funktionen mit gleicher Signatur verwenden. Jan H. schrieb: > Aus dem Struct muss der Zeiger dann komplett raus? Jain. Statdessen kommt die union da rein.
Gast
#5293003
Datum: 26.01.2018 06:50 > könntest Du die Funktionen auch variadisch > implementieren. Datum: 26.01.2018 06:52 > Wie stellt man das an? Bei dem (2 Minuten) Lerneifer, und dieser Googlehemmung, vermute ich mal, dass das Ganze von Anfang an ein fataler Irrtum ist. > Glaube nicht, dass dich der von dir eingeschlagene Weg zum > Ziel führt . Häufig kommen Leute an einem Punkt nicht > mehr weiter und bitten um Hilfe zu einem bestimmten Schritt, > ohne zu bemerken, dass der gewählte Pfad falsch ist. Es > kann viel Mühe kosten, dann doch noch zum Ziel zu gelangen. Aus: http://phpforum.de/forum/showthread.php?t=188250 Und wie Referenziere ich jetzt auf meine Funktionen die Ich aufrufen will?
Statt einer Union über eine Latte von verschiedenen Funktionszeigern könnte man alternativ auch einen einzigen Funktionszeiger verwenden, wo als Parameter ein Pointer auf eine Struct/Union übergeben wird, welche alle möglichen Parameter abdeckt. Die jeweils aufgerufene Funktion pickt sich dann die nötigen Parameter aus der Struct heraus. Das können je nach Kontext dann sogar verschiedene sein.
Gast
#5293127
Klingt so, wie wenn man einen Haufen globale Variable in eine struct packt und die struct bzw. einen Pointer darauf an Funktionen übergibt. Die Parameter müssen von irgendwo her kommen. Ich würde sie in ein struct packen, und wrapper funktionen erstellen:
Das könnte man teils mit Makros noch etwas vereinfachen. Jan H. schrieb: > Markus F. schrieb: >> aber deiner Beschreibung nach könntest Du die Funktionen auch variadisch >> implementieren. > Wie stellt man das an?
Hier mit einer variadischen Funktion sum() zusammen mit ihrem Aufruf, einmal direkt und einmal indirekt über einen Funktionszeiger. sum() bekommt als 1. Argument die Anzahl der zu addierenden Summanden, welche alle vom Typ int sind. Das "..." ist keine Obfuscation, sondern ein C/C++ Token. Eine varargs-Funktion muss wissen, wie sie die übergebenen Argumente zu interpretieren hat, und wieviel Argumente dies sind. Bei printf etc. wird dies z.B. über den Formatstring übermittelt. Im Beispiel werden nur int addiert, daher muss diese Info nicht übermittelt werden sondern nur die Anzahl der Argumente. Das wäre anders, wenn es z.B. ein Mix aus int, long, uint32_t, int* und float wäre. Die Funktion selbst wird etwas komplizierter, dafür sind die Aufrufe einfacher hinzuschreiben. Bei der Union-Lösung muss man z.B. abhängig von dem auszurufenden Prototypen eine Fallunterscheidung machen, und abhängig von den Fällen dann die Funktion aufrufen. Tatsächlich ist es da eher zweifelhaft, den Funktionszeiger per Type-Punning zurechtzubiegen, stattdessen könnte man auch direkt einen Cast verwenden, was den Vorteil hat, dass die Information an einer Stelle ist und nicht verteilt auf Union und Code:
...und bei einer LCD-Funktion kann man gleich einen printf-ähnlichen Ansatz wählen, um Text auszugeben oder Kommandos wie den Cursor an eine Bestimmte Position zu setzen, beispielsweise per "%@" was dann 2 unsigned Argumente für Zeilen- und Spaltenposition erwartet. > void handle7SEGMENT(void) > void led_show_temp(int16_t tempIn, uint8_t sense) > uint8_t *i2c_scan(uint8_t *buffer) Diese drei Funktionen tun vollkommen unterschiedliche Dinge. Wie wäre es, wenn du einfach DREI Funktionszeiger in deine Struct tust und einfach die richtige Funktion aufrufst?
Gast
#5296198
Wo ist das Problem mit dem "Union aller Funktionspointer" Ansatz? Für mich ist das jedenfalls die bisher beste Variante.
Gast
#5296219
MeineZweiCent schrieb: > Wo ist das Problem mit dem "Union aller Funktionspointer" Ansatz? Dass man in Nachhinein nicht mehr feststellen kann, welche Funktionssignatur denn jetzt die richtige ist. Damit ist ein solcher Zeiger recht nutzlos. Es sei denn, man führt auch noch die Signatur Information mit, damit man das zuordnen kann.
Gast
#5296265
Um den Ansatz zu Ende zu bringen und die Frage des TE zu beantworten,
trotzdem:
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
union ufp
{
void (*fpn0)(void);
void (*fpn1)(int16_t,uint8_t);
uint8_t*(*fpn2)(uint8_t*);
};
typedef struct
{
char *Name;
uint8_t numb;
union ufp fp;
}menue_t;
void HandleSevenSegment(void){
printf("I will handle the seven segment display\n\n");
return;
}
void LEDShowTemp(int16_t tempIn, uint8_t sense){
printf("And I will do some fancy LED show temperature stuff\n\n");
}
uint8_t *I2CScan(uint8_t *buffer){
printf("I usually do not use I2C bus\n\n");
return 0;
}
int main(void){
uint8_t* arg;
uint8_t* ret;
menue_t mainMenue[]=
{
{"Uhrzeit stellen", 0, .fp.fpn0 = &HandleSevenSegment},
{"Datum stellen", 1, .fp.fpn1 = &LEDShowTemp},
{"Bluetooth", 2, .fp.fpn2 = &I2CScan},
{"Neustart", 3, .fp.fpn1 = &LEDShowTemp},
{"Exit", 4, .fp.fpn0 = &HandleSevenSegment},
};
mainMenue[0].fp.fpn0();
mainMenue[1].fp.fpn1(3,6);
ret = mainMenue[2].fp.fpn2(arg);
return 0;
}
Gast
#5296272
Boa macht ihr Sachen. Das wird mit der Zeit vollkommen unübersichtlich und schwer wartbar. Die Variablen müssen ja trotzdem alle irgendwie (modul-)global sein damit das funktioniert. Und wehe wenn jemand das falsche Funktions-Argument initialisiert.... Vorschlag: nur void funktionpointer nutzen und den Rest in der entsprechenden Funktion auflösen....
Wer natürlich C++ sein eigen nennt, darf Lambda expressions nutzen (since C++11...) Beispiel:
Gast
#5296285
Weitere Nachteil der Vorgehensweise ala mainMenue[2].fp.fpn2(arg); Der Menücode muss die Variablen kenne, die übergeben werden. Beim void Funktionpointer können alle Variablen gekapselt bleiben, sprich: die Bluetooth Daten sind modulintern im Bluetooth Code. Nur die Einsprung Funktion muss public sein. Klaus schrieb: > typedef struct MENU { > const char *text; > void ( *fp )( void ); > } MENU_ENTRY; > > void DlgSetTime() { setTime(&xtime); } > void DlgSetDate() { setDate(&xDate); } > void DlgBluetooth() { bluetooth(&bt1, $bt2); } > > MENU_ENTRY menue[3]= > { > {"Uhrzeit stellen" , DlgSetTime }, > {"Datum stellen" , DlgSetDate }, > {"Bluetooth" , DlgBluetooth } > }; Hallo Klaus, das ist eine interessante Lösung. Gibt es einen speziellen Namen für diese Vorgehensweise? Irgendwo mit einem Link evtl. beschrieben? Habe Ich bis jetzt noch nicht gesehen, diese Art von Zuweisungen.
Gast
#5296485
Moin, was meinst Du mit Link? Zum Thema lambda expressions al "[]()" ? Jedes gute C++ Buch, oder http://en.cppreference.com/w/cpp/language/lambda Ansonsten habe ich die normale Variante mit void DlgXyz() schon mehrfach in GUIs eingesetzt (C Systeme). In der Literatur wird ab und zu der Begriff "Callback" Funktion genutzt. Sprich das Menü ruft zurück wenn etwas zu tun ist. (Öfters im Zusammenhang mit Fenstermanager, wenn diese z.B. ein Neuzeichnen eines Widgets anfordern …) Klaus schrieb: > nur void funktionpointer nutzen und den Rest in der entsprechenden > Funktion auflösen.... Interessanter Ansatz. So muß ich für jede einzustellende Variable eine extra Funktion schreiben. Der Gegenentwurf ist eine einzelne komplizierte Funktion, die weiträumig parametriert werden kann. Sieht dann so aus:
und wird so benutzt:
Irgendwo muß die Komplexität immer bleiben.
Gast
#5296522
Danke Klaus, super Lösung, wieder etwas gelernt!
Gast
#5296537
Bitte Es gibt natürlich Variationen. In komplexen Menüs hat man mehrere Aktionen. Ich habe auch schon obige Variante mit vielen structs genutzt. Aber dann habe ich meistens C++ im Einsatz, lege eine Basisklasse an, und leite entsprechende Klassen für Datentypen, Untermenüs etc. ab.
Gast
#5296703
Der Ansatz von Walter Tarpan ist auch gut, ich würde aber die Union vermeiden und etwas objektorientierter aufbauen. Komm aber frühestens heute Abend dazu ein Beispiel zu machen. Antwort schreibenBitte melde dich an, um einen Beitrag zu schreiben. |
Anzeige
|