Forum: PC-Programmierung Wozu 'inline' in C++?


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Unwissender (Gast)


Bewertung
-3 lesenswert
nicht lesenswert
Hallo, liebes Expertenforum.

https://www.cplusplus.com/articles/2LywvCM9/

"The inline functions are a C++ enhancement feature to increase the 
execution time of a program."

Wozu bitte sollte man sich noch extra Mühe geben, damit das Programm 
langsamer läuft?

von Εrnst B. (ernst)


Bewertung
0 lesenswert
nicht lesenswert
Aus dem Kontext wird doch eindeutig klar, dass der Autor an der Stelle 
eher "improve" schreiben wollte.
Vermute dass Englisch nicht seine Muttersprache ist, der weitere Text 
liest sich auch holprig.

von DoS (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Definitiv das falsche Wort. Inline wird benutzt, wenn man an bestimmten 
Stellen dem Compiler die "Freiheit" nehmen will, in eine ungewollte 
Richtung zu optimieren. Dazu sollte man aber schon wissen was man tut. 
Häufig sind Compiler schon recht effizient. Wenn man wirklich schnellen 
Code haben möchte, ist es manchmal ganz empfehlenswert, sich den 
Assembler/Maschinencode anzusehen, die der Compiler erstellt. Da reicht 
oft, in C/C++ den Code etwas anders zu formulieren um sehr viel 
schnelleren Code zu bekommen.

von Dussel (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Soweit ich weiß, ist inline sowieso nur eine Empfehlung an den Compiler.

von Unwissender (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antworten. Ja, das ist anscheinend ein Fehler.
"What is inline function :" sollte wohl eher "What is an inline 
function: " heißen und "The inline functions are" "Inline functions 
are". Daran hätte man das etwas holprige Englisch schon erkennen können.
Andererseits wird dieser Text in einer Box direkt oben auf der 
Ergebnisseite der Google-Suche als Kurzinfo angezeigt (alternierend mit 
ein oder zwei anderen) und wurde zuletzt 2014 geändert ...

Zur Sache selbst: Inzwischen habe ich mir diese FAQ durchgelesen:
https://isocpp.org/wiki/faq/inline-functions
Wie ihr bereits angedeutet habt, ist das alles wirklich ein wenig vage 
(muss es aber wohl auch sein, denn ob das "Inlinen" einer Funktion 
sinnvoll ist, hängt natürlich auch von der Zielplattform ab).

von Luther B. (luther-blissett)


Bewertung
0 lesenswert
nicht lesenswert
Die Bedeutung von inline als Optimierungshinweis (Funktion sollte in die 
aufrufende Funktion ausgerollt werden) ist obsolet, der Compiler 
entscheidet das heutzutage selber und braucht den Hinweis nicht.

Wichtig ist aber die zweite Bedeutung: Eine als inline definierte 
Funktion kann in mehreren translation units definiert werden - d.h. wenn 
ich eine inline Funktion f() in einer Headerdatei definiere und diese 
von N Sourcen inkludiere, dann habe ich nicht N Defintionen von f() (was 
einen Linkerfehler geben würde), sondern nur eine einzige und zwar in 
genau dem Sinne, dass die Adresse von f() überall im Programm die 
gleiche ist -- was nicht der Fall wäre, wenn man f() static definieren 
würde.

von c-hater (Gast)


Bewertung
-7 lesenswert
nicht lesenswert
Dussel schrieb:

> Soweit ich weiß, ist inline sowieso nur eine Empfehlung an den Compiler.

So ist es. Absolut hassenswert. Nö, der Compiler weiß halt nicht in 
jedem Fall, ob Inlining effizienter (im Sinn der Gesamtanwendung) wäre, 
tut aber so als wüßte er es und handelt entsprechend.

Ganz klar ein NoGo. Unbrauchbares Werkzeug.

von Mikro 7. (mikro77)


Bewertung
0 lesenswert
nicht lesenswert
Vielleicht für den einen oder anderen interessant:

When to use inline function and when not to use it?
https://stackoverflow.com/questions/1932311/when-to-use-inline-function-and-when-not-to-use-it

static vs inline for functions implemented in header files
https://stackoverflow.com/questions/22102919/static-vs-inline-for-functions-implemented-in-header-files

von M.K. B. (mkbit)


Bewertung
0 lesenswert
nicht lesenswert
Luther B. schrieb:
> Wichtig ist aber die zweite Bedeutung

Das ist richtig und der Name Inline ist tatsächlich irreführend.
Bei Templates, die meistens im Header definiert sind ist das Inline 
implizit dabei.

von M.K. B. (mkbit)


Bewertung
0 lesenswert
nicht lesenswert
c-hater schrieb:
> Nö, der Compiler weiß halt nicht in jedem Fall, ob Inlining effizienter
> (im Sinn der Gesamtanwendung) wäre, tut aber so als wüßte er es und
> handelt entsprechend.

Im allgemeinen weiß er dass nicht, aber bei größeren Anwendungen weiß es 
der Entwickler auch nicht.
Wenn man die Performance misst, dann kann man es optimieren. Bei 
Compilern nennt sich das Profile-guided optimization.

von Sven B. (scummos)


Bewertung
0 lesenswert
nicht lesenswert
Meines Wissens ist das "inlining" vom Inline als veraltet zu betrachten. 
Compiler ignorieren diesen Hinweis meist eh.

Was das Keyword tatsächlich tut, ist die Linkage zu ändern. Du kannst 
"inline int x() {return 0;}" in einen Header schreiben und den in fünf 
translation units includen, aber wenn du das inline weglässt, gibt es 
ein "multiple definition of". Das ist auch der einzige Zweck, zu dem ich 
es heutzutage noch verwenden würde: für inline in Headern implementierte 
freie Funktionen.

: Bearbeitet durch User
von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
M.K. B. schrieb:
> Luther B. schrieb:
>> Wichtig ist aber die zweite Bedeutung
>
> Das ist richtig und der Name Inline ist tatsächlich irreführend.

Es wird halt dann benötigt, wenn man inlining ermöglichen möchte, indem 
man Funktionen im Header definiert. Wenn die Implementation außerhalb 
des Headers in einem .cpp-File steht, kann sie in einem anderen nicht 
inline expandiert werden, da der Compiler den Code an der Stelle nicht 
kennt. Wenn man sie aber in den Header reinschreibt, hat man in jeder 
Übersetzungseinheit, in der dieser eingebunden ist, eine eigene 
Definition der Funktion, was ohne "inline" nicht erlaubt ist.
In Zeiten von LTO ist das aber auch nicht mehr unbedingt nötig.

von Oliver S. (oliverso)


Bewertung
1 lesenswert
nicht lesenswert
Rolf M. schrieb:
> Es wird halt dann benötigt, wenn man inlining ermöglichen möchte, indem
> man Funktionen im Header definiert. Wenn die Implementation außerhalb
> des Headers in einem .cpp-File steht, kann sie in einem anderen nicht
> inline expandiert werden, da der Compiler den Code an der Stelle nicht
> kennt.

Das war mal ein Problem. Seit LTO klappt das auch mit Code im cpp-File.

c-hater schrieb:
> Ganz klar ein NoGo. Unbrauchbares Werkzeug.

Je nun, für diejenigen, die wissen, was sie tun, hat jeder Compiler auch 
noch einen Befehl zum zwangsweisen inlining parat. Das solltest du aber 
einheitlich auch wissen.

Oliver

: Bearbeitet durch User
von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
Oliver S. schrieb:
> Das war mal ein Problem. Seit LTO klappt das auch mit Code im cpp-File.

Hättest meinen Text bis zum Ende lesen sollen :)

Rolf M. schrieb:
> In Zeiten von LTO ist das aber auch nicht mehr unbedingt nötig.

von inliner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich halte inline für verdammt wichtig, wenn man Programmabschnitte hat, 
bei denen die Laufzeit wichtig ist. Wenn dieser Programmabschnitt aus 
vielen verschiedenen Funktionen besteht, die man zur übersichtlichen 
Strukturierung angelegt hat, dann will man nicht dass der Überbau der 
Funktionsaufrufe in den Maschinenkode kommt. Also macht man alle 
Funktionen inline damit der Compiler auch wirklich aus allen Funktionen 
eine einzelne erzeugt.

von Urlaubär (Gast)


Bewertung
0 lesenswert
nicht lesenswert

von Nop (Gast)


Bewertung
0 lesenswert
nicht lesenswert
inliner schrieb:
> Also macht man alle
> Funktionen inline damit der Compiler auch wirklich aus allen Funktionen
> eine einzelne erzeugt.

Genau das tut "inline" aber nicht, wie in diesem Thread bereits richtig 
angemerkt wurde.

von Sven B. (scummos)


Bewertung
0 lesenswert
nicht lesenswert
inliner schrieb:
> Also macht man alle
> Funktionen inline damit der Compiler auch wirklich aus allen Funktionen
> eine einzelne erzeugt.

Wie immer gilt: Überlass' das mikro-optimieren dem Compiler.

Oft wird Code durch Unrolling oder Inlining langsamer statt schneller. 
Es gibt auch andere Optimierungskriterien als wie schnell die 
Instruktionen hintereinander ausgeführt werden, z.B. Kosten für 
Instruction Fetch und Cache-Größe für die Instruktionen.

von dunky (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Ich wage einfach mal zu behaupten, das moderne Compiler jeden guten/sehr 
guten Programmierer um Längen schlagen was solche Microoptimierungen 
angeht.

von Rolf M. (rmagnus)


Bewertung
0 lesenswert
nicht lesenswert
dunky schrieb:
> Ich wage einfach mal zu behaupten, das moderne Compiler jeden guten/sehr
> guten Programmierer um Längen schlagen was solche Microoptimierungen
> angeht.

Insbesondere wenn man sich mal von den allersimpelsten Architekturen wie 
z.B. AVR entfernt. Da reicht es dann nicht mehr, stupide die Taktzyklen 
von Instruktionen zusammenzuzählen. Da können Dinge wie Caching-Effekte, 
Pipeline Stalls und superskalare Architekturen einen sehr großen 
Einfluss auf die Laufzeit haben.

von Oliver S. (oliverso)


Bewertung
0 lesenswert
nicht lesenswert
Was natürlich ein Vollblut-Assemblerprogrammierer alles im Schlaf 
überblicken und berücksichtigen kann ;)

Oliver

von udok (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
dunky schrieb:
> Ich wage einfach mal zu behaupten, das moderne Compiler jeden
> guten/sehr
> guten Programmierer um Längen schlagen was solche Microoptimierungen
> angeht.

Ich wage zu behaupten, dass du 0 Ahnung und eine grosse Klappe hast.

Schau dir mal die Intel Performance Libs an, oder die Assembler und
Vektorbibliothek von Agner Fog.
Da ist schon bei einer memcpy ein Faktor 2-20 zwischen einer vom 
Kompiler optimierten C Funktion und einer optimierten Asm Funktion 
drinnen.

von Sven B. (scummos)


Bewertung
1 lesenswert
nicht lesenswert
udok schrieb:
> Ich wage zu behaupten, dass du 0 Ahnung und eine grosse Klappe hast.
>
> Schau dir mal die Intel Performance Libs an, oder die Assembler und
> Vektorbibliothek von Agner Fog.
> Da ist schon bei einer memcpy ein Faktor 2-20 zwischen einer vom
> Kompiler optimierten C Funktion und einer optimierten Asm Funktion
> drinnen.

Jo, die ist aber von Leuten bei Intel geschrieben, die sich über Jahre 
mit so einem Kleinkram befassen. Die Aussage ist nicht "der C-Compiler 
kann das besser als ein Mensch", die Aussage ist "der C-Compiler kann 
das besser als DU (oder ich)".

Außerdem: ein memcpy auf x86, das 20 mal schneller ist als das aus der 
glibc? Das will ich sehen.

von Programmierer (Gast)


Bewertung
1 lesenswert
nicht lesenswert
Sven B. schrieb:
> Wie immer gilt: Überlass' das mikro-optimieren dem Compiler.
>
> Oft wird Code durch Unrolling oder Inlining langsamer statt schneller.

Nicht unbedingt. Das inlining kann mittels Constant-Folding dafür 
sorgen, dass ein ganzer Baum an (verschachtelten) inline-Aufrufen zu 
einem insgesamt relativ simplen Konstrukt zusammenschnurrt, was dann im 
Endeffekt kleiner und schneller als ein normaler Funktionsaufruf wird. 
Das kann man insbesondere bei Register-Bit-Fummeleien sinnvoll 
ausnutzen. Leider ist die Heuristik der Compiler nicht immer gut genug 
um zu erkennen dass das Inlining in diesen Fällen sinnvoll ist, weshalb 
man sich mit Compiler-spezifischen Attributen zum Erzwingen des Inlining 
helfen kann, z.B. "__attribute__((always_inline))" beim GCC.

von udok (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Sven B. schrieb:
> Außerdem: ein memcpy auf x86, das 20 mal schneller ist als das aus der
> glibc? Das will ich sehen.

Das will ich auch sehen :-)

https://sourceware.org/legacy-ml/libc-help/2008-08/msg00007.html

Ein Faktor 10 ist anscheinend drinnen gegenüber
dem gcc buildin bei unaligned Daten, x5 gegenüber der glibc.
Das sind aber nicht mehr ganz aktuelle Messungen, und
da müsste mal wer nachschauen, ob das noch immer so ist.

Ich schätze mal, das der gcc inzwischen besser geworden ist,
andererseits sind die Optimierungs Möglichkeiten bei modernen
i7 mit AVX512 auch gestiegen.

von udok (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe mich jetzt noch gespielt, und bin auf einen Faktor 30
zwischen der schnellsten und der langsamsten Funktion gekommen!

Dazu habe ich drei einfache memcpy() Funktionen geschrieben:

1. for Schleife
2. memcpy aus der libc (immer die MSVCRT)
3. movsb Assemblerbefehl

Das ganze mit drei Compilern übersetzt, und das Ergebnis
liegt zwischen 24 Bytes/CPU-Takt und 0.8 Bytes/Cpu-Takt.

Timing wurde mit dem Pentium Timestamp Counter gemessen,
die Funktion wurde 10000 mal aufgerufen, und das schnellste
Ergebnis zählt.

Laptop Prozessor ist:
Intel(R) Core(TM) i7-8850H CPU @ 2.60GHz, 2592 MHz, 6 Kern(e)

Die Compiler sind gut abgehangene cl.exe (MS) und icl.exe (Intel),
sowie ein moderner gcc, alle 64 Bit.

Genaue Ergebnisse sind im PDF.
/* dumb C solution */
void* testcpy(void *dst, void *src, size_t len)
{
    size_t n;
    BYTE *p = dst;
    BYTE *r = src;

    for (n = 0; n < len; n++)
        p[n] = r[n];

    return dst;
}

#elif SOLUTION == 1

/* libc memcpy solution */
void* testcpy(void *dst, void *src, size_t len)
{
    return memcpy(dst, src, len);
}

#elif SOLUTION == 2

/* simple libc independent memcpy based on "rep; movsb". */
void testcpy(char *dst, const char *src, size_t count)
{
#if defined(_WIN32)
    __movsb((BYTE*)dst, (const BYTE*)src, count);
#elif (defined(__GNUC__) || defined(__clang__))
    __asm__ __volatile__("rep; movsb"
        : [dst] "=D"(dst), [src] "=S"(src), [count] "=c"(count)
        : "[dst]"(dst), "[src]"(src), "[count]"(count));
#else
    #pragma message("using generic movsb implementation")
    /* horrendous code bloat with Intel compiler! */
    while (count--) *dst++ = *src++;
#endif
}

#else

    #pragma message("solution not implemented")

#endif

Beitrag #6493890 wurde von einem Moderator gelöscht.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.