Huhu,
Ich hab schon etwas hier und da gesucht, aber ich suche immernoch eine
klare Aussage, wie ich dem Compiler sagen kann, dass Funktionsaufrufe
einer Funktion IMMER geinlined werden soll und dass der Funktionskörper
nicht einzeln übersetzt wird (weil er ja nie über einen CALL aufgerufen
werden würde).
Mal findet man _inline_, dann inline, die einen sagen was von
Optimierung O2 und wiederum der andere erzählt was von attributen, die
das inlinen erzwingen. Alles habe ich in fast jeglicher Kombination
ausprobiert. Meistens wird die Funktion aber immernoch mit CALL
aufgerufen. Ein paar Ausdrücke wie zum Beispiel:
../time.h:11: sorry, unimplemented: inlining failed in call to 'rtc_irq': function body not available
2
../main.c:189: sorry, unimplemented: called from here
Vielleicht verstehe ich nicht so ganz, wie der Compiler hier arbeitet.
Dann würde ich vielleicht auch verstehen, wo sein Problem liegt.
Ich würde mich freuen, wenn hier mal einer der GCC Spezies unter die
Arme greifen könnte ;) Vielen Dank
PS: Ich verwende den AVR-GCC
Inlining wird -wenn ich es richtig verstehe- nicht vom Linker
abgewickelt, daher muss eine dafür vorgesehene Funktion auch in der
Headerdatei definiert (und nicht nur deklariert) werden.
Die von Dir geposteten Fehlermeldungen lassen jedenfalls darauf
schließen.
Der Funktionsname jedoch lässt darauf schließen, daß Du da einen
Interrupthandler hast ... wie stellst Du Dir bei dem das inlining vor?
Inline Funktionen müssen kompletten im Header File implementiert werden,
also nicht aufteilen in .h und .c
Das Inline sagt dem Compiler aber trotzdem nur, dass er es nach
Möglichkeit inlinen soll. Wenns ihm nicht passt (zB weil die Funktion zu
lange ist), wird ers aber trotzdem zu ner Funktion machen.
Den Code in die Headerdatei? Uff, das widerspricht irgndwie meinem
Verständnis von guter C-Programmierung *g
Eine andere Möglichkeit gibt es nicht?
>Der Funktionsname jedoch lässt darauf schließen, daß Du da einen>Interrupthandler hast ... wie stellst Du Dir bei dem das inlining vor?
Die Funktion wird in einem Interrupthandler aufgerufen. Deswegen heißt
sie so :-). Bzw diese Funktion MUSS zyklisch im Hauptprogramm aufgerufen
werden.
Danke für eure Antworten bisher.
hi,
in meinem verständnis zur ersten fehlermeldung:
versucht euch einmal in den compiler hineinzuversetzen. der gcc included
eine header-datei beim bearbeiten einer c-datei. da steht der prototyp
einer aufgerufenen routine als inline drin. was nun? er soll den code
inlinen, aber es ist ja keiner da. weil dieser erst in einer fremden
c-datei steckt. ergo fehler.
bye kosmo
> Uff, das widerspricht irgndwie meinem> Verständnis von guter C-Programmierung *g> Eine andere Möglichkeit gibt es nicht?
Stell dir mal vor, du wärest der Compiler.
Du weist was inlinen bedeutet? Ein Aufruf einer
Funktion wird durch den Funktionsinhalt selbst
ersetzt.
So jetzt kommt dein grosser Auftritt als Compiler.
Compilier mal in Gedanken folgenden Code. Du brauchst
keinen Assembler Code erzeugen. Tue einfach nur so als ob.
Hier kommt der Code:
inline void foo( void );
int main()
{
int i;
for( i = 0; i < 10; ++i )
foo();
}
Also dann compilier mal schön und dass du ja die
Funktion inlinest.
Wie, du kannst die nicht inlinen? Steht doch da, dass
du sie inlinen sollt.
Wie, du müsstest schon díe Funktion selbst sehen um
den Funktionsaufruf ersetzen zu können? Da ist doch
der Funktionsprototyp!
Wie, der reicht dir nicht?
Ist es jetzt klarer, was du zu tun hast?
Wenn du willst, dass der Compiler eine Funktion auch
inlinen kann, dann musst du ihm schon auch die Funktions-
definition selbst zeigen. Nur mit dem Prototypen alleine
kann der Compiler nichts anfangen, wenn er den Funktions-
aufruf durch den Funktionsinhalt ersetzen soll.
Wenn es dir widerstrebt, den Code in eine Datei mit
der Endung *.h zu setzen:
Dem Präprozessor ist es völlig Wurscht wie die Datei heist.
#include holt die angegebene Datei in den Text rein. Und wenn
du beim #include eine jpg Datei angibst, dann wird halt
vom Prärozessor die jpg Datei reingezogen.
Wenn es dir also widerstrebt die Datei iregendwas.h zu nennen,
dann nenne sie irgendwas.inc
#include "rtc_irq.inc"
und in rtc_irq.inc ist dann die vollständige Funktionsdefinition.
Das *.inc ändert nichts an der grundsätzlichen Vorgangsweise.
Es ist eigentlich nur dazu da um anzuzeigen, dass das eben
kein ganz normales Headerfile mit Protoypen ist. Nicht für den
Compiler, dem ist es egal wie die Datei heist; fur dich
als Programmierer.
Ein wesentliches Element zum Verständns warum manche Dinge
in C so sind wie sie sind, besteht darin, dass in C jedes
C File (im Fachjargon heist das eine 'Translation Unit')
unabhängig von allen anderen C Files kompiliert wird.
Das heist, wenn sich der Compiler ein File a.c vornimmt,
dann interessiert ihn nur dieses eine File. Selbst
wenn man, wie es beim gcc möglich ist, beim Compileraufruf
mehrere C Files zur compilierung angeben kann, so läuft
das nach dem Muster ab:
das erste File kompiliern
alle internen Tabellen des Compilers löschen
nächtes File kompilieren
alle internen Tabellen des Compilers löschen
nächstes File ...
Der Compiler hat also gewissermassen Scheuklappen. Der
kümmert sich nur darum, was er in dieser einen Translation
Unit vorfindet. Wenn du im File a.c eine Funktion aufrufst
und diese Funktion in einem anderen File, b.c, enthalten
ist, kümmert ihn nicht die Bohne, wie dieses File b.c
aussieht. Solange a.c compiliert wird, weiss der Compiler
noch nicht einmal, dass b.c überhaupt existiert. Geschweige
denn welche Funktionen da drinn sind oder wie die Funktionen
aussehen.
Deswegen braucht man in C auch die Prototypen. Den es gilt
nach wie vor: Der Compiler muss bei der compilierung darüber
informiert werden, wass sich so ausserhalb des begrenzten
Sichtfeldes dieser einen Translation Unit abspielt. Wenn
ich eine Funktion aufrufen möchte, dann ist für den Compiler
am Ort des Aufrufs nur interessant:
* gibt es diese Funktion überhaupt (könnte ja auch ein
Tippfehler im Funktionsnamen sein)
* welche Argumente nimmt diese Funktion. Anzahl und Typ
müssen gleich sein. Beim Typ gibt es dann noch den Fall
dass eventuell eine Typanpassung (sprich ein impliziter
cast) gemacht werden muss
* welchen Returnwert hat diese Funktion
All diese Informationen stecken im Prototypen drinnen. Das reicht
auch vollkommen aus um einen Aufruf einer Funktion zu übersetzen.
Ob es diese Funktion auch tatsächlich gibt und wie diese Funktion
tatsächlich implementiert ist, braucht der Compiler an dieser
Stelle nicht wissen. Das interessiert erst dann, wenn die
Translation Unit mit dieser Funktion drann kommt.
Nur: Beim inlinen wollen wir ja mehr. Wir wollen ja, dass
überhaupt kein Funktionsaufruf zustande kommt, sondern der
Quelltext der Funktion an der Stelle des Aufrufs eingesetzt
wird. Und dazu muss der Compiler selbstverständlich den Quelltext
auch sehen können. Daraus folgt aber wiederrum, dass der Quelltext
in irgendeiner Form in die Translation Unit hineingezogen werden
muss.
Hallo Karl Heinz,
Soweit versteh ich das. Also übernimmt das Inlinen der Compiler und
nicht der Linker (wie schon erwähnt).
Macht ja auch irgendwo Sinn, weil der Linker ja dann Funktionsaufrufe
wieder löschen müsste.
Naja, nochmal Danke für die Erläuterungen.
> Also übernimmt das Inlinen der Compiler und> nicht der Linker (wie schon erwähnt).
Bis vor kurzem hätte ich gesagt: Ja das stimmt.
Aber mitlerweile gibt es auch Linker, die inlineing
Aufgaben übernehmen können. Das ändert aber nicht
wirklich was am Prinzip. Konzeptionell bleibt
in C alles beim Alten, selbst wenn der Linker das
inlining übernehmen würde.
Bitte uebrigens als "static inline" deklarieren. Dann eruebrigt sich
(zusammen mit der Unterbringung im .h-File) meist auch das
__attribute__((always_inline)).