Forum: Mikrocontroller und Digitale Elektronik Funktionspointer in einer Struktur


von Jan H. (janiiix3)


Lesenswert?

Nabend
1
typedef struct MENU {        // Daten-Struktur für Menüeintrag
2
  const unsigned char *text;  // Zeiger auf den anzuzeigenden String
3
//  int8_t previous;        // Zahl für vorherigen Menüeintrag, benötigt für mehrzeilige Displays
4
//  int8_t next;          // Zahl für nachfolgenden Menüeintrag, benötigt für mehrzeilige Displays
5
    void ( *fp )( void );   // Funktionszeiger
6
} MENU_ENTRY;              // Stuktur "MENU"mit Variablennamen "MENU_ENTRY"
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?

von Dumdi D. (dumdidum)


Lesenswert?

Hm. Pointer auf void und eine struktur uebergeben auf die gecasted wird? 
Keine Ahnung ob das UB ist.

von A. S. (Gast)


Lesenswert?

Union aller benötigen FP.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

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?

: Bearbeitet durch User
von Jan H. (janiiix3)


Lesenswert?

Achim S. schrieb:
> Union aller benötigen FP.

Pseudo Code, wie soll das gehen?

von Jan H. (janiiix3)


Lesenswert?

> 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.

von S. R. (svenska)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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?

von A. S. (Gast)


Lesenswert?

1
union ufp
2
{
3
   void (*fpvv)(void);
4
   int (*fpiv)(void);
5
   int(*fpii)(int i);
6
   ...
7
}
8
9
Statt deinem fp im struckt:
10
11
  union ufp fp;
12
13
Und Aufruf dann z.B. mit
14
15
  MenuEntry.fp.fpvv();

von S. R. (svenska)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

Aus dem Struct muss der Zeiger dann komplett raus?
1
typedef struct
2
{
3
  char *Name;
4
  void (*fp)(void);  
5
}men_t;
6
7
union ufp 
8
{
9
  void (*fnc)(uint8_t);  
10
};
11
union ufp fp;
12
13
void serv(uint8_t x)
14
{
15
  
16
}
17
18
men_t Men[]=
19
{
20
  {"Testsoftware",serv}
21
};

von Markus F. (mfro)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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?

von Dumdi D. (dumdidum)


Lesenswert?

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?

von Jan H. (janiiix3)


Lesenswert?

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?
1
void handle7SEGMENT(void)
2
void led_show_temp(int16_t tempIn, uint8_t sense)
3
uint8_t *i2c_scan(uint8_t *buffer)

von Dumdi D. (dumdidum)


Lesenswert?

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.

von Dirk B. (dirkb2)


Lesenswert?

Jan H. schrieb:
> Aus dem Struct muss der Zeiger dann komplett raus?

Jain.

Statdessen kommt die union da rein.
1
union ufp 
2
{
3
  void (*fnc)(uint8_t);  
4
};
5
6
7
8
typedef struct
9
{
10
  char *Name;
11
  union ufp fp;
12
}men_t;

von Einer K. (Gast)


Lesenswert?

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

von Jan H. (janiiix3)


Lesenswert?

Und wie Referenziere ich jetzt auf meine Funktionen die Ich aufrufen 
will?
1
union ufp
2
{
3
  void (*fnc0)(uint8_t);
4
  void (*fnc)(void);
5
};
6
7
typedef struct
8
{
9
  char *Name;
10
  uint8_t numb;
11
  union ufp fp;
12
}menue_t;
13
14
menue_t mainMenue[]=
15
{
16
  {"Uhrzeit stellen"  ,0},
17
  {"Datum stellen"  ,1},
18
  {"Bluetooth"    ,2},
19
  {"Neustart"      ,3},
20
  {"Exit"        ,4},      
21
};
22
23
mainMenue[0].fp.fnc(); // hier sollte z.B die Funktion .: setTime() aufgerufen werden...

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

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.

von xxx (Gast)


Lesenswert?

Klingt so, wie wenn man einen Haufen globale Variable in eine struct 
packt und die struct bzw. einen Pointer darauf an Funktionen übergibt.

von Daniel A. (daniel-a)


Lesenswert?

Die Parameter müssen von irgendwo her kommen. Ich würde sie in ein 
struct packen, und wrapper funktionen erstellen:
1
struct menu {
2
  const char* name;
3
  void (*func)(struct menu* menu);
4
  void* params;
5
};
6
7
void some_function(int a, int b);
8
9
struct some_function_menu_params {
10
  int a;
11
  int b;
12
};
13
14
void some_function_menu_wrapper(struct menu* menu){
15
  struct some_function_menu_params* params = menu->params;
16
  some_function(params->a, params->b);
17
}
18
19
struct menu mainMenue[]=
20
{
21
  {"Tue was", some_function_menu_wrapper, (struct some_function_menu_params[]){{1,2}}},
22
  {"Tue was 2", some_function_menu_wrapper, (struct some_function_menu_params[]){{2,3}}},
23
};

Das könnte man teils mit Makros noch etwas vereinfachen.

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Jan H. schrieb:
> Markus F. schrieb:
>> aber deiner Beschreibung nach könntest Du die Funktionen auch variadisch
>> implementieren.
> Wie stellt man das an?
1
#include <stdint.h>
2
3
extern int sum (uint8_t, ...);
4
5
#include <stdarg.h>
6
7
int sum (uint8_t n_args, ...)
8
{
9
    va_list args;
10
    va_start (args, n_args /* Last named arg */);
11
12
    int s = 0;
13
    for (uint8_t n = 0; n < n_args; n++)
14
    {
15
        s += va_arg (args, int);
16
    }
17
18
    va_end (args);
19
    return s;
20
}
21
22
int (*pfunc)(uint8_t, ...) = sum;
23
24
int main()
25
{
26
    return pfunc (3, 11, 22, 33) + sum (1, -66);
27
}

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:
1
#include <stdint.h>
2
#include <stdlib.h>
3
4
int sum_f (void *f, uint8_t n_args, int arg1, int arg2, int arg3)
5
{
6
    int s = 0;
7
    switch (n_args)
8
    {
9
        default: abort();
10
        case 0: return ((int(*)(void)) f) ();
11
        case 1: return ((int(*)(int)) f) (arg1);
12
        case 2: return ((int(*)(int,int)) f) (arg1, arg2);
13
        case 3: return ((int(*)(int,int,int)) f) (arg1, arg2, arg3);
14
    }
15
}

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

...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.

: Bearbeitet durch User
von S. R. (svenska)


Lesenswert?

> 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?

von MeineZweiCent (Gast)


Lesenswert?

Wo ist das Problem mit dem "Union aller Funktionspointer" Ansatz? Für 
mich ist das jedenfalls die bisher beste Variante.

von Einer K. (Gast)


Lesenswert?

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.

von MeineZweiCent (Gast)


Lesenswert?

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;
}

von Klaus (Gast)


Lesenswert?

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....
1
typedef struct MENU {
2
   const char *text;
3
   void ( *fp )( void );   
4
} MENU_ENTRY;  
5
6
void DlgSetTime()   { setTime(&xtime); }
7
void DlgSetDate()   { setDate(&xDate); }
8
void DlgBluetooth() { bluetooth(&bt1, $bt2); }
9
10
MENU_ENTRY menue[3]=
11
{
12
  {"Uhrzeit stellen"  , DlgSetTime },
13
  {"Datum stellen"    , DlgSetDate },
14
  {"Bluetooth"        , DlgBluetooth }    
15
};


Wer natürlich C++ sein eigen nennt, darf Lambda expressions nutzen 
(since C++11...)
Beispiel:
1
  {"Bluetooth"        , []{bluetooth(%bt1, &bt2);} }

von Klaus (Gast)


Lesenswert?

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.

von Jan H. (janiiix3)


Lesenswert?

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.

von Klaus (Gast)


Lesenswert?

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 …)

von Walter T. (nicolas)


Lesenswert?

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:
1
  typedef enum
2
    {
3
        nothing,
4
    voidFcn,
5
    uint8,
6
    uint16,
7
    int8,
8
    int16,
9
    #if MENU_SUPPORT_FLOAT
10
        float32,
11
    #endif
12
    endmarker,
13
    exitMenu,
14
  }
15
  type_t;
16
17
18
19
    // Menue-Eintraege: Zu startende Funktionen, zu aendernde Variablen
20
    // Die Reihenfolge macht es uebersichtlicher, Menutext und Variableninhalt separat
21
    // zu speichern.
22
    // Ein Eintrag sieht dann z.B. wie folgt aus:
23
    // { FLSTEXT1, .Uint8={ .type=uint8, .ptr=&var, .min=1, .max=255, .inc=5} }
24
    // { FLSTEXT2, .VoidFcn={ voidFcn, &foo }       }
25
    __extension__ typedef struct
26
    {
27
      constflash char *menutext; // Menueeintrag/Funktionsname
28
29
        union
30
      {
31
        // Generisch
32
        struct
33
        {
34
          type_t type;               // Datentyp:
35
                         // Bei function pointer wird die Funktion
36
                         // gestartet, bei Zeigern auf normale Daten
37
                         // der Datentyp im Menue bearbeitet.
38
        } All;
39
40
        // Container void-void-Funktionen
41
        struct
42
        {
43
          type_t type;               // Datentyp
44
          voidFcn_t ptr;             // Funktionszeiger
45
        } VoidFcn;
46
47
        // Container uint8_t-Variable
48
        struct
49
        {
50
          type_t type;               // Datentyp
51
          uint8_t *ptr;              // Zeiger auf Variablentypen
52
          uint8_t min;               // Untere Grenze
53
          uint8_t max;               // Obere Grenze
54
          uint8_t inc;               // Inkrement
55
        } Uint8;
56
57
        // Container int8_t-Variable
58
        struct
59
        {
60
          type_t type;               // Datentyp
61
          int8_t *ptr;               // Zeiger auf Variablentypen
62
          int8_t min;                // Untere Grenze
63
          int8_t max;                // Obere Grenze
64
          int8_t inc;                // Inkrement
65
        } Int8;
66
67
        // Container uint16_t-Variable
68
        struct
69
        {
70
          type_t type;               // Datentyp
71
          uint16_t *ptr;             // Zeiger auf Variablentypen
72
          uint16_t min;              // Untere Grenze
73
          uint16_t max;              // Obere Grenze
74
          uint16_t inc;              // Inkrement
75
        } Uint16;
76
77
        // Container int16_t-Variable
78
        struct
79
        {
80
          type_t type;               // Datentyp
81
          int16_t *ptr;              // Zeiger auf Variablentypen
82
          int16_t min;               // Untere Grenze
83
          int16_t max;               // Obere Grenze
84
          int16_t inc;               // Inkrement
85
        } Int16;
86
87
            #if MENU_SUPPORT_FLOAT
88
        // Container float32_t-Variable
89
        struct
90
        {
91
          type_t type;               // Datentyp
92
          float32_t *ptr;            // Zeiger auf Variablentypen
93
          float32_t min;             // Untere Grenze
94
          float32_t max;             // Obere Grenze
95
          float32_t inc;             // Inkrement
96
        } Float32;
97
            #endif
98
99
        };
100
    } Menuitem_t;                   // Struct wird terminiert mit type=endmarker

und wird so benutzt:
1
constflash char MT_TESTBENCH_HEADLINE[] = "Stepper Testbench";
2
constflash char MT_TESTBENCH_VELOCITY[] = "Velocity   :%6i";
3
constflash char MT_TESTBENCH_STEPMODE[] = "StepMode   :%6i  "; 
4
constflash char MT_TESTBENCH_CURRENT[]  = "Current    :%6.1f mA";
5
6
constflash Menuitem_t TestbenchMenuData[] =
7
{
8
    { MT_TESTBENCH_VELOCITY, .Int16 = {int16, &(TbdAct.velocity), .min = INT16_MIN, .max = INT16_MAX, .inc = 1} },
9
    { MT_TESTBENCH_STEPMODE, .Uint8 = {uint8, &(TbdAct.stepMode), .min = 0,         .max = 4,         .inc = 1} },
10
    { MT_TESTBENCH_CURRENT , .Float32 = {float32 , &(TbdAct.current_mA), .min=.0f, .max=4000.0f, .inc=31.25f  } },
11
    { MT_NULL              , .All   = {nothing                                                                } }, // Leerzeile
12
    { MT_QUIT        , .All   = {exitMenu                                                               } },
13
    { MT_NULL              , .All   = {endmarker                                                              } },
14
};

Irgendwo muß die Komplexität immer bleiben.

: Bearbeitet durch User
von MeineZweiCent (Gast)


Lesenswert?

Danke Klaus, super Lösung, wieder etwas gelernt!

von Klaus (Gast)


Lesenswert?

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.

von Klaus (Gast)


Lesenswert?

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.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.