Forum: Compiler & IDEs Mehrere Quelldateien, inline und __attribute__((always_inline))


von T. H. (pumpkin) Benutzerseite


Lesenswert?

Moin!

Ich habe ein Problem eine inline-Funktion aufzurufen und dabei das 
Inlining zu erzwingen. Folgendes Beispiel sollte das Problem 
reproduzieren:

1
// header.h
2
3
inline void bar(void) __attribute__((always_inline));
4
5
// ...
1
// A.c
2
3
#include "header.h"
4
5
void
6
foo()
7
{
8
  bar();
9
}
1
// B.c
2
3
#include "header.h"
4
5
inline void
6
bar(void)
7
{
8
  // Do something.
9
}
10
11
// ...

Der GCC bricht das Kompilieren mit

1
bfin-elf-gcc -I./include/ -g -mcpu=bf537 -std=gnu99 -Wall -pedantic -Os -save-temps -Winline   -c -o A.o A.c
2
events.c: In Funktion »foo«:
3
./include/header.h:129: nicht implementiert: »inline« beim Aufruf von »bar« gescheitert: function body not available
4
A.c:90: nicht implementiert: von hier aufgerufen

Scheint also als ob inline nicht geht weil er das Objekt nicht greifen 
kann?! Also Kontrolle indem alles in eine Quelldatei kommt:

1
// header.h
2
3
inline void bar(void) __attribute__((always_inline));
4
5
// ...
1
// A.c
2
3
#include "header.h"
4
5
void
6
foo()
7
{
8
  bar();
9
}
10
11
inline void
12
bar(void)
13
{
14
  // Do something.
15
}

Et voila, er kompiliert durch, ein Blick ins ASM-Listing bestätigt das 
ordnungsgemäße Inlinen (BTW: Jedoch nicht bei abgeschalteter 
Optimierung, was imho nicht zur Aussage in der Doku passt).

Nochwas am Rande. Wenn ich das __attribute__((always_inline)) entferne 
meckert er:

1
bfin-elf-gcc -I./include/ -g -mcpu=bf537 -std=gnu99 -Wall -pedantic -Os -save-temps -Winline   -c -o events.o events.c
2
A.c: In Funktion »foo«:
3
A.c:147: Warnung: »inline« beim Aufruf von »bar« gescheitert: --param max-inline-insns-single limit reached
4
A.c:90: Warnung: von hier aufgerufen

Wie bekomme ich aber den GCC dazu das über Quelldateigrenzen hinweg zu 
realisieren? Liegt es vllt am gnu99-Schalter - die Doku ist etwas knapp?

Cheers
TH

Edit: gcc-Version 4.1.2 (ADI svn)

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

AFAIK geht das nicht. Wie soll der Compiler die Funktion "inlinen" 
können wenn er die Größe eben selbiger nicht kennt? Du mußt die Funktion 
direkt im Header (als static inline) implementieren. Dann solltest du 
den gewünschten Effekt erreichen.

Matthias

von Rolf Magnus (Gast)


Lesenswert?

> Scheint also als ob inline nicht geht weil er das Objekt nicht greifen
> kann?!

Es ist zwar richtig, daß er das Objekt nicht "greifen" kann, aber das 
würde ihm auch nichts bringen. Er braucht auch den Quellcode.


> Wie bekomme ich aber den GCC dazu das über Quelldateigrenzen hinweg zu
> realisieren?

Gar nicht. Um eine Funktion inlinen zu können, braucht der Compiler 
natürlich deren Quelltext. Also muß die Implementation an der Stelle, wo 
die Funktion aufgerufen wird, bekannt sein durch vorherige Definition in 
derselben Quelldatei oder einem inkludierten Header.

von Peter D. (peda)


Lesenswert?

Eine Inline-Funktion erzeugt wie ein Define den Code erst beim Aufruf.
Sie gehört also wie ein Define ins h-File.

Der Unterschied zum Define ist nur die strengere Typ-Prüfung.


Peter

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


Lesenswert?

Peter Dannegger wrote:

> Der Unterschied zum Define ist nur die strengere Typ-Prüfung.

<nitpickmode>
Es gibt noch mehr Unterschiede, beispielsweise die Möglichkeit, einen
Wert aus der Funktion zurück zu geben und trotzdem auch lokale
Variablen innerhalb der Funktion zur Verfügung zu haben (die oftmals
das Formulieren vereinfachen).  Zwar kann GCC auch einen braced block
als rechte Seite eines Ausdrucks benutzen (und daraus gewissermaßen
einen Wert zurück geben), aber das ist im Gegensatz zur Inline-Funktion
kein Standard-C.
</nitpickmode>

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Peter Dannegger wrote:
> Eine Inline-Funktion erzeugt wie ein Define den Code erst beim Aufruf.
> Sie gehört also wie ein Define ins h-File.
>
> Der Unterschied zum Define ist nur die strengere Typ-Prüfung.

Nicht ganz, ein Define ist reiner Textersatz (geschieht also im 
Präprozessor, nicht im Compiler) während Inlining innerhalb des 
Compilers umgesetzt wird. Etwa ist es nicht egal, ob bei foo(++x) foo 
als Makro oder als Inline-Funktion zur Verfügung gestellt wird.

@pumpkin

Zunächst ist es ungewohnt, den Quellcode in nen Header zu schreiben. 
Aber das ist das Vorgehen bei static inline.

Die Alternative wäre extern inline, was aber wohl nicht das leistet, was 
du willst: Im C-Modul, wo die so gekennzeichnete Funktion implementiert 
wird, wird sie (wenn möglich) geinlint, der Compiler erzeugt aber 
zusätzlich eine Implementierung der Funktion, falls sie von extern 
referenziert wird. Dazu muss ja eine Implementierung vorliegen. In dem 
Fall hätte man die Funktion zwar in nem C-Modul, aber nichts gewonnen. 
In anderen Modulen könnte sie nicht geinlint werden, und im 
implementierenden Modul wird sie vermutlich nicht gerufen.

von T. H. (pumpkin) Benutzerseite


Lesenswert?

Moin moin!

Also wie gedacht, er braucht den Code. Es ist allerdings schade, dass es 
da keinen Mechanismus (evtl. in Kombination mit dem Linker?) gibt der 
das ermöglicht.

Aber danke für die Kommentare!

von Marcus H. (mharnisch) Benutzerseite


Lesenswert?

T. H. wrote:
> Es ist allerdings schade, dass es da keinen Mechanismus (evtl. in
> Kombination mit dem Linker?) gibt der das ermöglicht.

Gibt es. Wird beispielsweise beim ARM linker "branch inlining" genannt. 
Das kann allerdings nur im Einzelfall funktionieren. Der Linker kann ja 
nicht einfach eine beliebig große Einfügung vornehmen. Beim ARM Linker 
ist diese Funktion daher auf Unterprogramme beschränkt, die nicht mehr 
Platz beanspruchen, als der Unterprogrammaufruf selbst (ein Wort, also 
maximal zwei Befehle).

Gruß
Marcus
http://www.doulos.com/arm/

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.