Forum: Compiler & IDEs Funktionen richtig prototypisieren?!


von Marc L. (marc_l)


Lesenswert?

Hallo,

ich habe ein paar Fragen zum Prototypisieren von Funktionen mit static 
inline und nur inline.
Alle Prototypen habe ich in der dazugehörigen .h-Datei.

Ich verwende u.a. die KS0108-Lib von Ape.
Dort wird im Original folgende Funktion prototypisiert:
1
inline uint8_t ks0108ReadData(void);
Das ergibt folgende Warnung:
1
warning: inline function 'ks0108ReadData' declared but never defined
Lasse ich das inline weg, dann kommt die Fehlermeldung nicht mehr und 
das Programm scheint aber trotzdem richtig zu arbeiten.

Dann habe ich noch eine andere Funktion, die ich verwende.
Und zwar ist das die Keydebouncing-Funktion von PeDa, die ich für eine 
4x4-Tastermatrix umgeschrieben habe.
Dort gebe ich folgendes an:
1
static inline uint16_t key_scan(void);
Das ergibt folgende Warnung:
1
warning: 'key_scan' declared 'static' but never defined
Wenn ich nur
1
uint16_t key_scan(void);
schreibe, kommt folgende Fehlermeldung:
1
error: static declaration of 'key_scan' follows non-static declaration
...und es wird auf die vorhandene static inline-Funktion gezeigt:
1
error: previous declaration of 'key_scan' was here
Kommentiere ich
1
static inline uint16_t key_scan(void);
vollständig aus, so bekomme ich keinen Fehler und keine Warnung mehr.
Das Programm arbeitet so ohne Probleme.

Was ich nun wissen möchte:
Muss man static inline bzw. nur inline prototypisieren?
Wenn ja, wie bekommt man das ohne Fehler- und Warnmeldungen hin?

Danke,
Marc

von Karl H. (kbuchegg)


Lesenswert?

Marc L. schrieb:
> Hallo,
>
> ich habe ein paar Fragen zum Prototypisieren von Funktionen mit static
> inline und nur inline.
> Alle Prototypen habe ich in der dazugehörigen .h-Datei.
>
> Ich verwende u.a. die KS0108-Lib von Ape.
> Dort wird im Original folgende Funktion prototypisiert:
>
1
> inline uint8_t ks0108ReadData(void);
2
>
> Das ergibt folgende Warnung:
> [code]
> warning: inline function 'ks0108ReadData' declared but never defined

Weißt du was inline macht?

Es fordert den Compiler auf, den Funktionsinhalt an der Stelle de 
Aufrufes einzusetzen. Anstelle eines Funktionsaufrufes wird dort also 
der Funktionskörper eingebaut.

Das machen wir beide mal
1
inline uint8_t foo( void );
2
3
4
int main()
5
{
6
  int i = 5;
7
8
  foo();
9
}

also: welcher Code ergibt sich, wenn du den Funktionsaufruf durch den 
Körper der Funktion foo ersetzt?

Wie, das kannst du nicht, weil du ja nicht weißt, was alles in der 
Funktion foo gemacht wird?


Genau das verlangst du aber von deinem Compiler! Wenn du das nicht 
kannst, wie soll es dann der Compiler können?


Und so
1
inline uint8_t foo( void )
2
{
3
  int j = 5;
4
  int k = 2 * j;
5
}
6
7
8
int main()
9
{
10
  int i = 5;
11
12
  foo();
13
}

können sowohl du als auch der Compiler die Funktion inlinen. Hier ist 
die Funktion tatsächlich definiert und nicht nur deklariert, also 
vereinbart dass es eine Funktion dieses Namens gibt
Heraus kommt:
1
int main()
2
{
3
  int i = 5;
4
5
  {
6
    int j = 5;
7
    int k = 2 * j;
8
  }
9
}

Der Funktionskörper der Funktion foo wurde an der Aufrufstelle eingebaut

>
1
> static inline uint16_t key_scan(void);
2
>
> Das ergibt folgende Warnung:
> [code]
> warning: 'key_scan' declared 'static' but never defined


declared but never defined. Genau das gleiche Symptom


> Wenn ich nur
>
1
> uint16_t key_scan(void);
2
>
> schreibe, kommt folgende Fehlermeldung:
> [code]
> error: static declaration of 'key_scan' follows non-static declaration

Du hast 2 Protoypen. Einmal einen mit static und einmal einen ohne 
static.


> Kommentiere ich
>
1
> static inline uint16_t key_scan(void);
2
>
> vollständig aus, so bekomme ich keinen Fehler und keine Warnung mehr.
> Das Programm arbeitet so ohne Probleme.
>
> Was ich nun wissen möchte:
> Muss man static inline bzw. nur inline prototypisieren?
> Wenn ja, wie bekommt man das ohne Fehler- und Warnmeldungen hin?

Indem man darüber nachdenkt was static bzw in line eigentlich machen 
(gegebenenfalls im Lehrbuch nachschlagen) und das Gelesene dann in die 
Praxis umsetzen.


>
> Danke,
> Marc

von Marc L. (marc_l)


Lesenswert?

Hallo Karl Heinz Buchegger,

du hast mein Problem super auseinander genommen!
Das hat mir sehr geholfen!

Karl Heinz Buchegger schrieb:
> Indem man darüber nachdenkt was static bzw in line eigentlich machen
> (gegebenenfalls im Lehrbuch nachschlagen) und das Gelesene dann in die
> Praxis umsetzen.
Ich habe mir das bereits im C-Buch angeguckt, aber anscheinend sind die 
Erklärungen in dem Buch nicht so wertvoll und verständnisreich wie 
deine!
Vielen Dank, nun kann ich das Problem von einem anderen Standpunkt 
betrachten und es erscheint mir nun logisch.

Danke,
Marc

von Martin K. (mkmannheim) Benutzerseite


Lesenswert?

Vielleicht sollte K.H. ein Buch schreiben?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

"inline" sollte man nach Möglichkeit nie allein benutzen, sondern
immer als "static inline".  C99 hat die inline-Funktionalität für
nicht-static deklarierte Funktionen leicht anders standardisiert,
als GCC sie vor der Standardisierung durch C99 implementiert hat.
Wenn der Compiler sich dann entscheidet, die Funktion nicht
inline zu erweitern (was GCC bspw. regelmäßig bei -O0 macht), dann
muss man zusätzlich zur inline deklarierten Funktion noch eine
nicht-inline-Variante anbieten, ansonsten bekommt man einen
Linkerfehler.

Ja, ist schräg, aber ist Standard. ;-)  Mit "static inline" liegt
man dagegen immer richtig.  Wenn sich der Compiler dann gegen das
Inlining entscheidet, hat man halt im schlimmsten Falle in jeder
Übersetzungseinheit eine Kopie der Funktion, aber da man ja
eigentlich erwartet hatte, für jeden Aufruf eine eigene Kopie
der Funktion zu bekommen, kann das dann nicht wirklich tragisch
sein.

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.