in einem avr-gcc-Programm habe ich folgende Deklarationen:
typedef void (*MENU_SELECTED_FN)(void *);
typedef struct menu_item_s {
struct menu_item_s *next; // pointer to next item, may be NULL
MENU_SELECTED_FN sel_fn; // function called when the menu is selected, may be NULL
...
} MENU_ITEM;
Die Selektionsfunktionen bekommen das MENU_ITEM als Parameter:
void menu_sel_beep(MENU_ITEM *item) {
...
}
Es werden dann Variablen initialisiert, z.B.
MENU_ITEM menu_beep PROGMEM = {
&menu_delay,
&menu_sel_beep, // warning: initialization from incompatible pointer type
...
};
Der Code l�uft (im Simulator wenigstens).
Mein Problem ist die warning: "initialization from incompatible pointer type".
Was ich gerne m�chte, ist ein Funktionstyp
typedef void (*MENU_SELECTED_FN)(MENU_ITEM *);
Das w�rde dann wohl die Warnung erledigen.
Es gelingt mir allerdings mit meinen beschr�nkten C-Kenntnissen nicht, eine funktionierende
L�sung daf�r auszuhirnen. Ich dachte an einen Forward, etwa:
typedef struct MENU_ITEM;
um den Typ des Funktionsarguments vorab festzulegen (statt void *). Geht leider so nicht.
Wei� jemand eine M�glichkeit, die l�stigen Warnings loszuwerden oder muss ich damit leben?
-Wall m�chte ich weiterhin verwenden.
TIA, Leo
--
Swearwords are dung for the day.
> Was ich gerne möchte, ist ein Funktionstyp
>
> typedef void (*MENU_SELECTED_FN)(MENU_ITEM *);
>
> Das würde dann wohl die Warnung erledigen.
Dann tu doch das - Du kannst diese Deklaration ja nach dem typedef
plazieren.
Sollte das nicht gehen, blieben noch folgende Möglichkeiten:
1.
typedef struct menu_item_s MENU_ITEM;
typedef void (*MENU_SELECTED_FN)(MENU_ITEM *);
2.
typedef void (*MENU_SELECTED_FN)(struct menu_item_s *);
Thomas
Nun, der Punkt ist ja, dass ich den Funktionstyp in der struct verwenden m�chte.
Daher muss ich ihn doch vorher definieren, dachte ich. Der Compiler denkt auch so ;-)
> Sollte das nicht gehen, blieben noch folgende M�glichkeiten:
>
> 1.
> typedef struct menu_item_s MENU_ITEM;
> typedef void (*MENU_SELECTED_FN)(MENU_ITEM *);
Das ergibt dann weiter unten:
error: redefinition of typedef 'MENU_ITEM'
> 2.
> typedef void (*MENU_SELECTED_FN)(struct menu_item_s *);
warning: 'struct menu_item_s' declared inside parameter list
warning: its scope is only this definition or declaration, which is probably not what you want
Das behebt auch die urspr�nglich genannten Warnung nicht. So it's definitely not what I want.
Gru�, Leo
So geht's:
typedef struct menu_item_s {
struct menu_item_s *next; // pointer to next item, may be NULL
void (*sel_fn)(struct menu_item_s *);
...
} MENU_ITEM;
Eigentlich logisch... <headdesk> Sorry f�r die Umst�nde...
Gru�, Leo
Es genuegt, wenn Du ihn deklarierts, dh
struct blah;
typedef void make_blah_blah(struct blah *)
Funktionzeiger kann man dann als
make_blah_blah *parlamentsrede;
definieren.
Ich hab's jetzt mal so ausprobiert:
Deklarationen:
struct MENU_ITEM;
typedef void MENU_SEL_FN(struct MENU_ITEM *);
typedef struct menu_item_s {
struct menu_item_s *next;
MENU_SEL_FN *sel_fn;
...
} MENU_ITEM;
Definitionen:
MENU_ITEM menu_beep PROGMEM = {
&menu_delay,
&menu_sel_beep, --> warning: initialization from incompatible pointer type
...
}
War es das, was Du meintest? Wenn ja, hilft es nix, die Warnung bleibt dieselbe.
F�r den Compiler sind "struct MENU_ITEM" und der "typedef struct { } MENU_ITEM"
anscheinend nicht das gleiche.
> Ich hab's jetzt mal so ausprobiert:
>
> Deklarationen:
>
> struct MENU_ITEM;
> typedef void MENU_SEL_FN(struct MENU_ITEM *);
> typedef struct menu_item_s {
> struct menu_item_s *next;
> MENU_SEL_FN *sel_fn;
> ...
> } MENU_ITEM;
>
> Definitionen:
> MENU_ITEM menu_beep PROGMEM = {
> &menu_delay,
> &menu_sel_beep, --> warning: initialization from incompatible pointer type
> ....
> }
>
> War es das, was Du meintest? Wenn ja, hilft es nix, die Warnung bleibt dieselbe.
> Fᅵr den Compiler sind "struct MENU_ITEM" und der "typedef struct { } MENU_ITEM"
> anscheinend nicht das gleiche.
Dein Problem, so scheint mir, liegt darin, struct MENU_ITEM und
MENU_ITEM auseinander zu halten. Das sind zwei vollkommen verschiedene
Dinge:
- MENU_ITEM ist ein Alias fᅵr struct menu_item_s.
- struct MENU_ITEM existiert in Deinem Programm nicht.
Gruᅵ. Claus
> War es das, was Du meintest? Wenn ja, hilft es nix, die Warnung bleibt dieselbe.
> Fᅵr den Compiler sind "struct MENU_ITEM" und der "typedef struct { } MENU_ITEM"
> anscheinend nicht das gleiche.
Es hilft mir manchmal, die struct-definitionen, typedefs,
Funktionszeiger usw. nicht alle in eins zu "vermanschen".
Dann entsteht weniger natᅵrliches Durcheinander bei der
"Zeigerkardinalitᅵt" der Deklarationen. (Letzteres ist
wahrscheinlich der Grund fᅵr die Warnungen, die du bekommst).
Das folgende ist so angelegt, dass dein compiler hoffentlich
ᅵber die Stellen meckert, die Hinweise auf ungeeignete
Deklarationen/Annahmen geben kᅵnnen:
#include <stdlib.h>
struct S1;
typedef void (*F1)(struct S1*); /* Ein Zeigertyp... */
typedef void F2 (struct S1*);
typedef struct S1 T1;
typedef void (*F3)(T1*);
typedef void F4 (T1*);
struct S1 {
struct S1 *next;
F1 sel_fn1;
F1 *sel_fn1_pp;
F2 *sel_fn2;
F3 sel_fn3;
F3 *sel_fn3_pp;
F4 *sel_fn4;
};
void fn(struct S1* a) {
;
}
int main()
{
struct S1 s = {
NULL, /* next */
&fn, /* F1 */
&fn, /* F1* */
&fn, /* F2* */
&fn, /* F3 */
&fn, /* F3* */
&fn /* F4* */
};
s.sel_fn1(NULL);
s.sel_fn1_pp(NULL);
s.sel_fn2(NULL);
s.sel_fn3(NULL);
s.sel_fn3_pp(NULL);
s.sel_fn4(NULL);
}
Ob man zu jedem "struct Typname" ein bedeutungsgleiches
"TYPNAME" typedef-inieren mᅵchte, ist Geschmackssache.
Ja, ich sehe gerade, dass meine Annahmen �ber das C-Typsystem falsch waren.
Ich glaub, ich w�nsch mir den K&R zu Weihnachten...
Das kommt davon, wenn man Codesnippets aus dem Netz �bernimmt, ohne sie richtig
zu verstehen ;-) Naja, man lernt nie aus.
> Das folgende ist so angelegt, dass dein compiler hoffentlich
> �ber die Stellen meckert, die Hinweise auf ungeeignete
> Deklarationen/Annahmen geben k�nnen:
[snip code]
Interessantes Beispiel, danke. Ich gehe das mal durch.
Viele Gr��e, Leo
[...]
> struct MENU_ITEM;
> typedef void MENU_SEL_FN(struct MENU_ITEM *);
Das muesste zweimal struct menu_item_s sein. Auch die vorgeschlagene
Variante
typedef struct menu_item_s MENU_ITEM;
gefolgt von der Definition des Funktionszeigertyps ist korrekt,
> typedef struct menu_item_s {
> struct menu_item_s *next;
> MENU_SEL_FN *sel_fn;
> ...
> } MENU_ITEM;
lediglich muesste dann hier der typedef-Teil entfernt werden, denn der
Alias wurde ja bereits definiert.
[...]
> Ob man zu jedem "struct Typname" ein bedeutungsgleiches
> "TYPNAME" typedef-inieren m�chte, ist Geschmackssache.
Es ist ausserdem eine dumme Idee. Sogenannte 'structure tags'
existieren in einem eigenen Namensraum, was es zB ermoeglicht, structs
sinnvolle Namen zu geben ohne diese Namen deswegen zu
'verbrauchen'. ZB kann man eine Variable namens 'punkt' definieren,
deren Typ 'struct punkt' ist ohne dass man irgendwelche 'homegrown'
Affixe benutzen muss. Gipfel der Idiotie diesbezueglich (alles schon
gesehen):
typedef struct punkt {
int x, y;
} struct_punkt;
oder
typedef struct punkt {
int x, y;
} punkt_struct;
Damit kommen 'wir' auch gleich zu Problem #2: In C gibt es
ausschliesslich Wertparameter. Normalerweise ist es sogar dann nicht
sinnvoll, Strukturen als Werte an eine Unterroutine zu uebergeben,
wenn diese nicht modifiziert werden sollen, denn entsprechende
'calling conventions' sind typischerweise aufwendiger als die fuer
'native Typen' und Strukturen sind auch haeufig deutlich groesser als
diese, was zu hohem Kopieraufwand fuehren kann. Um beides vermeiden,
uebergibt man ueblicherweise Zeiger auf Strukturen. Angenommen jemand
benutzt eine Bibliothek die C-Kennzeichungen unterschiedlicher
Typ-Repraesentationen, dh das *-Suffix fuer Zeiger oder eben das
struct-Praefix fuer Strukturen hinter beliebigen
Buchstabenkombinationen versteckt, und dieser jemand muss selber von
der Bibliothek verwaltete Objekte zwischen Unterroutinen hin und her
uebergeben, woher kann jetzt dieser jemand wissen, wann es sinnvoll
waere, ein Objekt indirekt zu uebergeben, und wann nicht?
<rant>
Ich wage die Behauptung, dass ein nennenswerter Teil aller
Softwarefehler sich in Luft aufloesen wuerde, wenn man mal all diesen
Mathetikern, Infotikern und Physipaten, sei es unter Gewaltandrohung,
beibiegen koennte, dass sie sich gefaelligst einfach und moeglichst
allgemeinverstaendlich auszudruecken haben, obwohl ihnen das ein
aesthetischer Greuel ist. Sinnvoll geschriebener Code macht einen
langweiligen Eindruck.
</rant>
[...]
> Ob man zu jedem "struct Typname" ein bedeutungsgleiches
oder
Mathetikern, Infotikern und Physipathen, sei es unter Gewaltandrohung,