Forum: Mikrocontroller und Digitale Elektronik C: Struct function pointer prototype


von Walter T. (nicolas)


Lesenswert?

Guten Morgen,

ich habe in einem struct einen Funktionszeiger auf eine Funktion, die 
den struct als Parameter übergeben bekommt:
1
typedef struct IconData_s
2
{
3
    void (*fcn) (IconData_t);
4
    uint8_t slot;
5
    int8_t thisState;
6
    int8_t lastState;
7
}
8
IconData_t;
Das funktioniert. Die Funktion läßt sich beim Iterieren über das struct 
array aufrufen.

Will ich stattedessen eine Funktion mit Funktionszeiger als Argument 
aufrufen, schlägt der Build fehl:
1
typedef struct IconData_s
2
{
3
    void (*fcn) (IconData_t *);
4
    uint8_t slot;
5
    int8_t thisState;
6
    int8_t lastState;
7
}
8
IconData_t;
Stattdessen muß ich mit einem "incomplete type struct" hantieren:
1
struct IconData_s;
2
typedef struct IconData_s IconData_t;
3
4
struct IconData_s
5
{
6
    void (*fcn) (IconData_t *);
7
    uint8_t slot;
8
    int8_t thisState;
9
    int8_t lastState;
10
};


Was ist für den Compiler (hier: ARM-GCC) der große Unterschied?

von mh (Gast)


Lesenswert?

Walter T. schrieb:
> Guten Morgen,
>
> ich habe in einem struct einen Funktionszeiger auf eine Funktion, die
> den struct als Parameter übergeben bekommt:typedef struct IconData_s
> {
>     void (*fcn) (IconData_t);
>     uint8_t slot;
>     int8_t thisState;
>     int8_t lastState;
> }
> IconData_t;
> Das funktioniert. Die Funktion läßt sich beim Iterieren über das struct
> array aufrufen.

Bist du sicher, dass das funktioniert? Würde mich wundern.
IcondData_t ist in dieser Zeile noch nicht bekannt.
1
void (*fcn) (IconData_t);
Wenn du die Warnungen einschaltest, sagt dir dein Compiler das auch.
1
warning: parameter names (without types) in function declaration
2
    3 |     void (*fcn) (IconData_t);
3
      |     ^~~~
Der Wortlaut der Warnung ist in diesem Fall nicht ideal, aber sollte 
einen in die richtige Richtung weisen.

von mh (Gast)


Lesenswert?

mh schrieb:
> Wenn du die Warnungen einschaltest, sagt dir dein Compiler das auch.

Korrektur: Selbst der ARM gcc 4.5.4 gibt ohne extra Optionen eine 
Warnung aus.

von Walter T. (nicolas)


Lesenswert?

Die Warnung habe ich auch.

Es funktioniert insoweit, als daß das richtige passiert, d.h. die 
Funktion läßt sich korrekt aufrufen und schreibt auch einen Zahlenwert 
aus dem struct korrekt in die Konsole. Aber klar. Die Warnung ist da.

Nur das eine ist ein Fehler - das andere eine Warnung - was ist für den 
Kompiler der große Unterschied?

von A. S. (Gast)


Lesenswert?

Walter T. schrieb:
> void (*fcn) (IconData_t);

In dieser Zeile ist IconData_t keine Struktur, sondern default int. Du 
wirst einen Compiler mit C89 verwenden.

Das Stichwort ist "vorwärtsdeklaration" und das tut nun wirklich nicht 
so weh, wie es "incomplete type" vermuten lässt.

von Martin (Gast)


Lesenswert?

Folgendes sollte funktionieren:
1
typedef struct IconData_s
2
{
3
    void (*fcn) ( struct IconData_s *);
4
    uint8_t slot;
5
    int8_t thisState;
6
    int8_t lastState;
7
}
8
IconData_t;

Gruß Martin

Beitrag #5923472 wurde vom Autor gelöscht.
von Walter T. (nicolas)


Lesenswert?

A. S. schrieb:
> In dieser Zeile ist IconData_t keine Struktur, sondern default int.

Warum? Ich hätte einen undefinierten Typ erwartet, also einen Fehler.

: Bearbeitet durch User
von mh (Gast)


Lesenswert?

Weil es der Standard vorschreibt. Der nächste Satz, den du nicht zitiert 
hast, weißt darauf hin.

von Yalu X. (yalu) (Moderator)


Lesenswert?

Dieses

1
    void (*fcn) (IconData_t);

ist K&R-C und steht für

1
    void (*fcn) (int IconData_t);

in ISO-C. IconData_t ist also nicht der Argumenttyp, sondern der
Argumentname.

Deswegen erscheint die Warnung

1
warning: parameter names (without types) in function declaration

(Name ist da, aber Typ fehlt)

: Bearbeitet durch Moderator
von Walter T. (nicolas)


Lesenswert?

Yalu X. schrieb:
> in ISO-C. IconData_t ist also nicht der Argumenttyp, sondern der
> Argumentname.

Danke für die Klarstellung! Ich hatte ganz vergessen, daß man den 
Argumentnamen hier auch schon deklarieren darf, weil er ja eh ignoriert 
wird.

von Oliver S. (oliverso)


Lesenswert?

Das wird deutlich, wenn man
1
void (*fcn) (IconData_t a);
draus macht.
Dann kommt der erwartete "error: unknown type name 'IconData_t'"

Lösung:
1
void (*fcn) (struct IconData_s a);

Oliver

von Yalu X. (yalu) (Moderator)


Lesenswert?

Clang liefert hier sogar einen Error:

1
test.c:5:18: error: a parameter list without types is only allowed in a
2
      function definition
3
    void (*fcn) (IconData_t);
4
                 ^

Ich habe auf die Schnelle zwar nicht die entsprechende Stelle in der
ISO-Norm gefunden, aber das die Fehlermeldung ist vermutlich
gerechtfertigt, da in K&R-C reine Deklarationen keine Argumentliste
enthalten.

Hier zeigt sich ein weiteres Mal die Problematik von typedef, die darin
besteht, dass syntaktisch nicht zwischen Typ- und Variablennamen
unterschieden werden kann. Im konkreten Fall wird ein Identifier, der
eigentlich als Typname gedacht ist, aber noch nicht deklariert wurde,
als Variablenname interpretiert.

: Bearbeitet durch Moderator
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.