Hallo liebe Forum-User!
Ich bin gerade dabei mir selber C beizubringen und experimentiere mit
Funktionszeigern. Nun stoße ich auf folgendes Problem:
Im nachfolgenden Code habe ich einen "typedef struct" mit dem Namen
"device_function". Dieser soll eine Liste mit Funktionen enthalten. Als
Parameter wird ein int-Wert übergeben
1
#include<stdio.h>
2
#include<stdlib.h>
3
4
typedefstruct{
5
constchar*text;
6
intzahl;
7
}param;
8
9
typedefstruct{
10
constchar*description;
11
void(*funct)(int);
12
intparameter;
13
}device_function;
14
15
voidmach_was(void*p){
16
inta=*(int*)p;
17
printf("Erledige eine Aufgabe: %i\n",a);
18
}
19
20
voidmach_noch_was(void*p){
21
inta=*(int*)p;
22
printf("Erledige eine zweite Aufgabe: %i\n",a);
23
}
24
25
device_functionprogramm_functions[]={
26
{"Funktion 1",mach_was,123},
27
{"Funktion 2",mach_noch_was,123},
28
};
29
30
staticintfunctions_count=sizeof(programm_functions)/sizeof(programm_functions[0]);// Anzahl der Einträge
Das Programm funktioniert soweit wunderbar, es kommt die Ausgabe:
1
Funktion 1
2
Erledige eine Aufgabe: 123
3
4
~~~~~~~~~~~~~~~~~~~~
5
Funktion 2
6
Erledige eine zweite Aufgabe: 123
7
8
~~~~~~~~~~~~~~~~~~~~
9
10
Process returned 0 (0x0) execution time : 0.027 s
11
Press any key to continue.
Wenn ich aber jetzt aber anstelle des Integer-Wertes den struct "param"
verwende, und diesen von void nach param caste, erhalte ich nachfolgende
Fehlermeldung vom Compiler:
1
#include<stdio.h>
2
#include<stdlib.h>
3
4
typedefstruct{
5
constchar*text;
6
intzahl;
7
}param;
8
9
typedefstruct{
10
constchar*description;
11
void(*funct)(int);
12
paramparameter;
13
}device_function;
14
15
voidmach_was(void*p){
16
parama=*(param*)p;
17
printf("Erledige eine Aufgabe: %i\n",a->zahl);
18
}
19
20
voidmach_noch_was(void*p){
21
parama=*(param*)p;
22
printf("Erledige eine zweite Aufgabe: %i\n",a->zahl);
23
}
24
25
device_functionprogramm_functions[]={
26
{"Funktion 1",mach_was,{"Test",123}},
27
{"Funktion 2",mach_noch_was,{"Test",1234}},
28
};
29
30
staticintfunctions_count=sizeof(programm_functions)/sizeof(programm_functions[0]);// Anzahl der Einträge
||=== Build: Debug in funktionszeiger (compiler: GNU GCC Compiler) ===|
2
C:\gcc\funktionszeiger\main.c||In function 'mach_was':|
3
C:\gcc\funktionszeiger\main.c|17|error: invalid type argument of '->' (have 'param')|
4
C:\gcc\funktionszeiger\main.c||In function 'mach_noch_was':|
5
C:\gcc\funktionszeiger\main.c|22|error: invalid type argument of '->' (have 'param')|
6
C:\gcc\funktionszeiger\main.c|26|warning: initialization from incompatible pointer type [enabled by default]|
7
C:\gcc\funktionszeiger\main.c|26|warning: (near initialization for 'programm_functions[0].funct') [enabled by default]|
8
C:\gcc\funktionszeiger\main.c|27|warning: initialization from incompatible pointer type [enabled by default]|
9
C:\gcc\funktionszeiger\main.c|27|warning: (near initialization for 'programm_functions[1].funct') [enabled by default]|
10
C:\gcc\funktionszeiger\main.c||In function 'main':|
11
C:\gcc\funktionszeiger\main.c|40|warning: passing argument 1 of 'programm_functions[i].funct' makes integer from pointer without a cast [enabled by default]|
12
C:\gcc\funktionszeiger\main.c|40|note: expected 'int' but argument is of type 'struct param *'|
Matthias Haas schrieb:> Wo liegt mein Denkfehler im obrigen Programm?
void (*funct)(int);
void mach_noch_was(void* p) {
warum nicht hier auch den richtigen Parameter verwenden? Dann könntest
du die ganze Casterei sparen.
Ich möchte eine flexible Struktur schaffen, und der einen Funktion z.B.
einen Struct übergeben können, der anderen einen String, einer dritten
Funktion einen Integer-Wert. (union)
Matthias Haas schrieb:> void (*funct)(int);> void mach_was(void* p)> device_function programm_functions[] = {> {"Funktion 1", mach_was,
Das der implizite cast von void(*)(void*) nach void(*)(int);
funktioniert ist reines glück!
> param a = *(param*)p;> a->zahl
a ist kein pointer! Versuche
param* a = (param*)p;
oder
a.zahl
Matthias Haas schrieb:> Ich möchte eine flexible Struktur schaffen, und der einen Funktion z.B.> einen Struct übergeben können, der anderen einen String, einer dritten> Funktion einen Integer-Wert.
und wie willst du diese werte in deiner Struktur ablegen?
Matthias Haas schrieb:> Ich möchte eine flexible Struktur schaffen, und der einen Funktion z.B.> einen Struct übergeben können, der anderen einen String, einer dritten> Funktion einen Integer-Wert. (union)
Wenn du sowieso schon so etwas planst
1
typedefunion{
2
constchar*text;
3
intzahl;
4
}funcArg;
dann solltest du das auch durchziehen. Deine Funktionen bekommen dann
einen Pointer auf eine derartige Union, müssen also der Aufrufkonvention
1
voidfunc(intargType,funcArg*arg)
2
{
3
...
4
}
genügen. Denn sonst schaffst du es ja nicht "beliebige" Argumente (im
Rahmen dessen, was durch die union möglich ist) in die Funktionen zu
bringen.
Damit ist dein Funktionspointer aber anders anzulegen und auch die
Funktionen sind anders auszuführen
(Ich fasse die union und die Typkennzeichnung, welcher Member der union
gültig ist noch in einer struct zusammen. Damit kann die Funktion
erkennen, was sie tytsächlich übergeben bekommen hat und entsprechend
reagieren. Entweder indem sie sich nach dem Datentyp richtet oder indem
sie mitteilt 'Damit kann ich nichts anfangen')
1
typedefunion{
2
constchar*text;
3
intzahl;
4
}funcArg;
5
6
#define TEXT_ARG 0
7
#define INT_ARG 1
8
9
typedefstruct
10
{
11
intargType;
12
funcArgarg;
13
}funcParam;
14
15
typedefvoid(*funcPtr)(funcParam*arg);
16
17
typedefstruct{
18
constchar*description;
19
funcPtrfunct;
20
paramparameter;
21
}device_function;
22
23
voidmach_was(funcParam*p){
24
if(p->argType==INT_ARG)
25
printf("mach_was: Mit Int Arg aufgerufen - %d\n",p->arg.zahl);
26
27
elseif(p->argType==TEXT_ARG)
28
printf("mach_was: mit Text Arg aufgerufen - %s\n",p.arg.text);
29
}
30
31
voidmach_noch_was(funcParam*p){
32
if(p->argType!=INT_ARG)
33
printf("mach_noch_was: Fehler - Funktion mit ungültigem Argumenttyp aufgerufen\n";
mach um void Zeiger einen großen Bogen wenn du kannst. Mit void Zeigern
legst du die Typüberwachung des Compilers in letzter Konsequenz einfach
lahm. Und das ist selten eine gute Idee, wenn es auch anders geht. Dinge
einfach auf Biegen und Brechen zurecht zu casten, ist meistens eine
schlechte Lösung - weil DU als Programmierer für die Richtigkeit ganz
alleine verantwortlich bist. Und das geht öfter in die Hose als einem
lieb ist. Da ist es schon besser, wenn man auf die Casts verzichten kann
und der Compiler wenigsten ein bischen über die Schulter schaut und
kontrolliert.
Matthias Haas schrieb:> typedef struct {> const char *text;> int zahl;> } param;
Bringe nach Möglichkeit die Dinge nicht mutwillig durcheinander. Ja, ich
weiß, daß die C-Freaks am liebsten alles zusammenziehen wollen, aber ein
sauberer Stil ist das nicht. Mit typedef kannst du einem bestehenden Typ
einen neuen Namen geben, dazu dient dieses Statement. Zum eigentlichen
Definieren eines Typs ist das nicht gedacht.
struct TParam
{ const char* Text;
int Zahl;
}
So sähe das im Grunde aus. Nun kannst du dir aussuchen, ob du es
anschließend so schreiben willst:
#define param struct TParam
oder so
typedef struct TParam param;
was im Grunde auf dasselbe hinausläuft. Du kannst aber auch schlicht und
einfach mit TParam weiterarbeiten, ohne das #define und ohne das
typedef. Es ist nur, daß du dann das struct beim Deklarieren von
Variablen mit dazuschreiben mußt.
Viele Leute machen den Denkfehler, daß sie glauben, mit typedef
tatsächlich einen Typ definieren zu können, aber das ist eben falsch und
führt langfristig nur zu Verständnisproblemen das typedef betreffend.
W.S.
W.S. schrieb:> Matthias Haas schrieb:>> typedef struct {>> const char *text;>> int zahl;>> } param;>> Bringe nach Möglichkeit die Dinge nicht mutwillig durcheinander. Ja, ich> weiß, daß die C-Freaks am liebsten alles zusammenziehen wollen, aber ein> sauberer Stil ist das nicht. Mit typedef kannst du einem bestehenden Typ> einen neuen Namen geben, dazu dient dieses Statement. Zum eigentlichen> Definieren eines Typs ist das nicht gedacht.Genau dafür ist es gedacht.
Der Typ "struct { const char *text, int zahl }" wird als Typ "param"
definiert.
> #define param struct TParam
Unnötig und mieser Stil.
> typedef struct TParam param;
struct TParam ist unnötig.
Johann L. schrieb:>> typedef struct TParam param;>> struct TParam ist unnötig.
... und ich möchte hinzufügen:
und belastet nur den Namensraum mit dem Namen der struct, den (zumindest
in diesem Fall) keiner braucht.