Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Forward einer typedef struct für Funktionsargument?

0 views
Skip to first unread message

Leo Meyer

unread,
Dec 17, 2009, 5:22:00 AM12/17/09
to
Hallo,

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.


Thomas Rachel

unread,
Dec 17, 2009, 6:18:50 AM12/17/09
to
Leo Meyer schrieb:

> 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

Leo Meyer

unread,
Dec 17, 2009, 6:54:50 AM12/17/09
to
Thomas Rachel wrote:
>> 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.

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

Leo Meyer

unread,
Dec 17, 2009, 7:19:04 AM12/17/09
to
Nachtrag mit L�sung:

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

Rainer Weikusat

unread,
Dec 17, 2009, 8:26:28 AM12/17/09
to
"Leo Meyer" <leom...@gmx.de> writes:
> Thomas Rachel wrote:
>>> 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.
>
> 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 ;-)

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.

Leo Meyer

unread,
Dec 17, 2009, 9:00:04 AM12/17/09
to
Rainer Weikusat wrote:
> 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.

Claus Reibenstein

unread,
Dec 17, 2009, 10:28:54 AM12/17/09
to
Leo Meyer schrieb:

> 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

Georg Bauhaus

unread,
Dec 17, 2009, 10:16:35 AM12/17/09
to
Leo Meyer schrieb:

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

Leo Meyer

unread,
Dec 17, 2009, 11:14:46 AM12/17/09
to
Claus Reibenstein wrote:
> 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.

Ja, ich sehe gerade, dass meine Annahmen �ber das C-Typsystem falsch waren.
Ich glaub, ich w�nsch mir den K&R zu Weihnachten...

Leo Meyer

unread,
Dec 17, 2009, 11:15:01 AM12/17/09
to
Georg Bauhaus wrote:
> 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 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

Rainer Weikusat

unread,
Dec 17, 2009, 11:50:27 AM12/17/09
to
"Leo Meyer" <leom...@gmx.de> writes:
> Rainer Weikusat wrote:
>> struct blah;

[...]

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

Rainer Weikusat

unread,
Dec 17, 2009, 12:24:05 PM12/17/09
to
Georg Bauhaus <rm.dash...@futureapps.de> writes:

[...]

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

Rainer Weikusat

unread,
Dec 17, 2009, 12:24:32 PM12/17/09
to
Georg Bauhaus <rm.dash...@futureapps.de> writes:

[...]

> Ob man zu jedem "struct Typname" ein bedeutungsgleiches

oder

Mathetikern, Infotikern und Physipathen, sei es unter Gewaltandrohung,

0 new messages