Mehrere Quelldateien, inline und __attribute__((always_inline))

OP Persönliche Seite #1095704
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)
Gast #1095751
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.
Moderator Persönliche Seite #1096074
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>
Persönliche Seite #1096084
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.
Persönliche Seite #1096613
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/

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren