C++ bietet Inline-Funktionen, um den Funktionsaufruf-Overhead zu reduzieren. Eine Inline-Funktion ist eine Funktion, die beim Aufruf in der Zeile erweitert wird. Wenn die Inline-Funktion aufgerufen wird, wird der gesamte Code der Inline-Funktion an der Stelle des Inline-Funktionsaufrufs eingefügt oder ersetzt. Diese Ersetzung wird vom C++-Compiler zur Kompilierungszeit durchgeführt. Eine Inline-Funktion kann die Effizienz steigern, wenn sie klein ist.
Syntax:
inline return-type function-name(parameters) { // function code }>
Denken Sie daran, dass Inlining nur eine Anfrage an den Compiler und kein Befehl ist. Der Compiler kann die Inlining-Anfrage ignorieren.
Der Compiler führt unter folgenden Umständen möglicherweise kein Inlining durch:
- Wenn eine Funktion eine Schleife enthält. ( für, während und tun-während )
- Wenn eine Funktion statische Variablen enthält.
- Wenn eine Funktion rekursiv ist.
- Wenn der Rückgabetyp einer Funktion ein anderer als void ist und die Rückgabeanweisung nicht im Funktionskörper vorhanden ist.
- Wenn eine Funktion eine switch- oder goto-Anweisung enthält.
Warum werden Inline-Funktionen verwendet?
Wenn das Programm den Funktionsaufrufbefehl ausführt, speichert die CPU die Speicheradresse des Befehls, der auf den Funktionsaufruf folgt, kopiert die Argumente der Funktion auf den Stapel und übergibt schließlich die Steuerung an die angegebene Funktion. Die CPU führt dann den Funktionscode aus, speichert den Rückgabewert der Funktion an einem vordefinierten Speicherort/Register und gibt die Kontrolle an die aufrufende Funktion zurück. Dies kann zu einem Mehraufwand führen, wenn die Ausführungszeit der Funktion kürzer ist als die Umschaltzeit von der aufrufenden Funktion zur aufgerufenen Funktion (Angerufener).
Bei Funktionen, die groß sind und/oder komplexe Aufgaben ausführen, ist der Overhead des Funktionsaufrufs im Vergleich zur Zeit, die die Funktion zur Ausführung benötigt, normalerweise unbedeutend. Bei kleinen, häufig verwendeten Funktionen ist die Zeit, die für den Funktionsaufruf benötigt wird, jedoch oft viel länger als die Zeit, die für die tatsächliche Ausführung des Funktionscodes benötigt wird. Dieser Overhead entsteht bei kleinen Funktionen, da die Ausführungszeit einer kleinen Funktion kürzer ist als die Umschaltzeit.
Vorteile von Inline-Funktionen:
- Es entsteht kein Funktionsaufruf-Overhead.
- Es spart außerdem den Overhead von Push/Pop-Variablen auf dem Stapel, wenn eine Funktion aufgerufen wird.
- Außerdem wird dadurch der Aufwand für einen Rückruf einer Funktion eingespart.
- Wenn Sie eine Funktion einbinden, können Sie dem Compiler ermöglichen, eine kontextspezifische Optimierung für den Hauptteil der Funktion durchzuführen. Für normale Funktionsaufrufe sind solche Optimierungen nicht möglich. Weitere Optimierungen können durch Berücksichtigung der Abläufe des aufrufenden Kontexts und des aufgerufenen Kontexts erzielt werden.
- Eine Inline-Funktion kann für eingebettete Systeme nützlich sein (wenn sie klein ist), da Inline weniger Code liefern kann als die Funktion „Preamble“ und „Return“.
Nachteile der Inline-Funktion:
- Die hinzugefügten Variablen aus der Inline-Funktion verbrauchen zusätzliche Register. Wenn nach der Inlining-Funktion die Variablenanzahl, die das Register verwenden wird, zunimmt, kann es zu einem Overhead bei der Ressourcennutzung der Registervariablen kommen. Das bedeutet, dass beim Ersetzen des Inline-Funktionskörpers zum Zeitpunkt des Funktionsaufrufs auch die Gesamtzahl der von der Funktion verwendeten Variablen eingefügt wird. Daher wird auch die Anzahl der Register erhöht, die für die Variablen verwendet werden. Wenn also die Anzahl der Inlining-Variablen nach der Funktion drastisch ansteigt, würde dies sicherlich zu einem Mehraufwand bei der Registerauslastung führen.
- Wenn Sie zu viele Inline-Funktionen verwenden, wird die Größe der ausführbaren Binärdatei aufgrund der Duplizierung desselben Codes groß.
- Zu viel Inlining kann auch die Trefferquote Ihres Befehls-Cache verringern und somit die Geschwindigkeit des Befehlsabrufs von der des Cache-Speichers auf die des Primärspeichers verringern.
- Die Inline-Funktion kann den Zeitaufwand für die Kompilierung erhöhen. Wenn jemand den Code innerhalb der Inline-Funktion ändert, muss die gesamte aufrufende Position neu kompiliert werden, da der Compiler den gesamten Code noch einmal ersetzen müsste, um die Änderungen widerzuspiegeln. Andernfalls wird mit dem alten fortgefahren Funktionalität.
- Inline-Funktionen sind für viele eingebettete Systeme möglicherweise nicht nützlich. Denn in eingebetteten Systemen ist die Codegröße wichtiger als die Geschwindigkeit.
- Inline-Funktionen können Thrashing verursachen, da Inlining die Größe der ausführbaren Binärdatei erhöhen kann. Durch Überlastung des Arbeitsspeichers wird die Leistung des Computers beeinträchtigt. Das folgende Programm demonstriert die Verwendung der Inline-Funktion.
Beispiel:
C++
#include> using> namespace> std;> inline> int> cube(>int> s) {>return> s * s * s; }> int> main()> {> >cout <<>'The cube of 3 is: '> << cube(3) <<>'
'>;> >return> 0;> }> |
>
>Ausgabe
The cube of 3 is: 27>
Inline-Funktionen und -Klassen
Es ist auch möglich, die Inline-Funktion innerhalb der Klasse zu definieren. Tatsächlich sind alle innerhalb der Klasse definierten Funktionen implizit inline. Somit gelten auch hier alle Einschränkungen der Inline-Funktionen. Wenn Sie eine Inline-Funktion explizit in der Klasse deklarieren müssen, deklarieren Sie die Funktion einfach innerhalb der Klasse und definieren Sie sie außerhalb der Klasse mit dem Schlüsselwort inline.
Syntax:
class S { public: inline int square(int s) // redundant use of inline { // this function is automatically inline // function body } };> Der obige Stil gilt als schlechter Programmierstil. Der beste Programmierstil besteht darin, einfach den Prototyp der Funktion in die Klasse zu schreiben und ihn als Inline in der Funktionsdefinition anzugeben.
Zum Beispiel:
class S { public: int square(int s); // declare the function }; inline int S::square(int s) // use inline prefix { }> Beispiel:
C++
// C++ Program to demonstrate inline functions and classes> #include> using> namespace> std;> class> operation {> >int> a, b, add, sub, mul;> >float> div>;> public>:> >void> get();> >void> sum();> >void> difference();> >void> product();> >void> division();> };> inline> void> operation ::get()> {> >cout <<>'Enter first value:'>;> >cin>> a;> >cout <<>'Enter second value:'>;> >cin>> b;> }> inline> void> operation ::sum()> {> >add = a + b;> >cout <<>'Addition of two numbers: '> << a + b <<>'
'>;> }> inline> void> operation ::difference()> {> >sub = a - b;> >cout <<>'Difference of two numbers: '> << a - b <<>'
'>;> }> inline> void> operation ::product()> {> >mul = a * b;> >cout <<>'Product of two numbers: '> << a * b <<>'
'>;> }> inline> void> operation ::division()> {> >div> = a / b;> >cout <<>'Division of two numbers: '> << a / b <<>'
'>;> }> int> main()> {> >cout <<>'Program using inline function
'>;> >operation s;> >s.get();> >s.sum();> >s.difference();> >s.product();> >s.division();> >return> 0;> }> |
>
int zu verdoppeln
>
Ausgabe:
Enter first value: 45 Enter second value: 15 Addition of two numbers: 60 Difference of two numbers: 30 Product of two numbers: 675 Division of two numbers: 3>
Was stimmt mit dem Makro nicht?
Leser, die mit der C-Sprache vertraut sind, wissen, dass die C-Sprache Makros verwendet. Der Präprozessor ersetzt alle Makroaufrufe direkt im Makrocode. Es wird empfohlen, immer die Inline-Funktion anstelle des Makros zu verwenden. Laut Dr. Bjarne Stroustrup sind die Ersteller von C++-Makros in C++ fast nie notwendig und fehleranfällig. Es gibt einige Probleme bei der Verwendung von Makros in C++. Das Makro kann nicht auf private Mitglieder der Klasse zugreifen. Makros sehen aus wie Funktionsaufrufe, sind es aber nicht.
Beispiel:
C++
// C++ Program to demonstrate working of macro> #include> using> namespace> std;> class> S {> >int> m;> public>:> >// error> #define MAC(S::m)> };> |
>
>
Ausgabe:
Error: '::' may not appear in macro parameter list #define MAC(S::m)>
Der C++-Compiler überprüft die Argumenttypen von Inline-Funktionen und notwendige Konvertierungen werden korrekt durchgeführt. Das Präprozessormakro ist dazu nicht in der Lage. Eine weitere Sache ist, dass die Makros vom Präprozessor und die Inline-Funktionen vom C++-Compiler verwaltet werden. Denken Sie daran: Es stimmt, dass alle innerhalb der Klasse definierten Funktionen implizit inline sind und der C++-Compiler Inline-Aufrufe dieser Funktionen ausführt, aber der C++-Compiler kann keine Inline-Aufrufe ausführen, wenn die Funktion virtuell ist. Der Grund dafür, dass eine virtuelle Funktion aufgerufen wird, wird zur Laufzeit und nicht zur Kompilierungszeit aufgelöst. Virtuell bedeutet Warten bis zur Laufzeit und Inline bedeutet während der Kompilierung. Wenn der Compiler nicht weiß, welche Funktion aufgerufen wird, wie kann er dann Inlining durchführen? Beachten Sie außerdem, dass es nur dann sinnvoll ist, die Funktion inline zu machen, wenn die Zeit, die während eines Funktionsaufrufs aufgewendet wird, größer ist als die Ausführungszeit des Funktionskörpers.
Ein Beispiel, bei dem die Inline-Funktion überhaupt keine Wirkung hat:
inline void show() { cout << 'value of S = ' << S << endl; }> Die Ausführung der obigen Funktion dauert relativ lange. Im Allgemeinen sollte eine Funktion, die eine Eingabe-Ausgabe-Operation (E/A) ausführt, nicht als Inline-Funktion definiert werden, da sie viel Zeit in Anspruch nimmt. Technisch gesehen ist das Inlining der show()-Funktion von begrenztem Wert, da die Zeit, die die I/O-Anweisung benötigt, den Overhead eines Funktionsaufrufs bei weitem übersteigt. Abhängig vom verwendeten Compiler zeigt der Compiler möglicherweise eine Warnung an, wenn die Funktion nicht inline erweitert wird.
Programmiersprachen wie Java und C# unterstützen keine Inline-Funktionen. In Java kann der Compiler jedoch Inlining durchführen, wenn die kleine finale Methode aufgerufen wird, da finale Methoden nicht von Unterklassen überschrieben werden können und der Aufruf einer finalen Methode zur Kompilierungszeit aufgelöst wird.
In C# kann der JIT-Compiler Code auch durch Inlining kleiner Funktionsaufrufe optimieren (z. B. das Ersetzen des Hauptteils einer kleinen Funktion, wenn diese in einer Schleife aufgerufen wird). Als Letztes sollten Sie bedenken, dass Inline-Funktionen eine wertvolle Funktion von C++ sind. Die ordnungsgemäße Verwendung von Inline-Funktionen kann zu einer Leistungssteigerung führen. Wenn Inline-Funktionen jedoch willkürlich verwendet werden, können sie keine besseren Ergebnisse liefern. Mit anderen Worten: Erwarten Sie keine bessere Leistung des Programms. Machen Sie nicht jede Funktion inline. Es ist besser, Inline-Funktionen so klein wie möglich zu halten.