Welche Vorteile bieten Inline Funktionen gegenüber Makros ??



  • Hey Leute , unser Professor will im Bezug auf die Prüfungsvorberietung wissen .
    Welche Vorteile Inline Fkt. gegenüber Makros haben ...??
    Ich wüsste nur diese beiden Vorzüge
    •Inline Funktionen benötigen weniger Zeit für call und return
    •Rekursion stellt Makroprozessor vor Problem welches er nicht lösen kann -> Inline Funktionen unterstützen Rekursion ..

    Welche Vorzüge könntet irh mir noch nennen ..??



  • Bacid90210 schrieb:

    Welche Vorteile Inline Fkt. gegenüber Makros haben ...??
    Ich wüsste nur diese beiden Vorzüge
    •Inline Funktionen benötigen weniger Zeit für call und return

    Ist das so? Weil Makros reine Textersetzungen sind die auf jedenfall an die Stelle eingetragen werden, bei inline ist dies zwar ein Ziel, aber der Compiler entscheidet ob der Code wirklich an die Stelle eingetragen wird.

    Ich sehe eher die Gefahren von Makros als den massiven Unterschied an:

    // Ungetestet:
    #define MAX(a, b) a > b ? a : b
    
    int main()
    {
      int a = MAX(1, 2);
      int b = MAX(++a, 3); => Teste mal was heraus kommt... (Tip: 3 ist es nicht)
    }
    


  • Bacid90210 schrieb:

    Hey Leute, unser Professor will im Bezug auf die Prüfungsvorberietung wissen.
    Welche Vorteile Inline Fkt. gegenüber Makros haben ...??
    Ich wüsste nur diese beiden Vorzüge
    •Inline Funktionen benötigen weniger Zeit für call und return

    auch gegenüber Makros? Ich denke nicht.

    Bacid90210 schrieb:

    •Rekursion stellt Makroprozessor vor Problem welches er nicht lösen kann -> Inline Funktionen unterstützen Rekursion ..

    Kann sein. (Ich bin kein Makrospezialist)

    Naja, da gibt's ja so einige Gründe. Mir fallen spontan diese Dinge ein: Bei Makros gibt's vielleicht mehr "Fallen", bedingt durch die einfache Textersetzung des Präprozessors während inline-Funktionen vom Compiler "verstanden" werden und ggf bessere Fehlermeldungen ausgeben können. Makros sind auch unabhängig vom "Scope". Sie lassen sich nicht auf einen mit {} geklammerten Scope beschränken. public inline-Funktionen sind in Klassen praktisch, um lesenden Zugriff auf Datenelemente bereitzustellen. Wenn Du so etwas mit einem Makro machen willst, bist du gezwungen die Datenelemente public zu deklarieren. So gesehen, fördern inline-Funktionen die Kapselung gegenüber Makros in diesem Fall.

    Hier ist mal ein bekanntes Beispiel einer "Falle":

    int foo();
    int bar();
    
    …
    
    int main()
    {
      …
      int z = max(foo(),bar());
      …
    }
    

    max als inline-Funktion zu schreiben, wobei die Funktionen foo und bar jeweils nur einmal aufgerufen werden ist einfach. Wenn Du das mit einem Makro so machen willst, musst Du glaub'ich auf Compilererweiterungen zurückgreifen. Also ein

    #define max(a,b) ((b)<(a)?(a):(b))
    

    ist hier nicht so praktisch, da foo und bar jeweils doppelt aufgerufen werden.

    u.s.w....

    kk



  • - Der Compiler kann inline ignorieren, wenn die Funktion zu groß ist und die Funktion nicht in den cache passt (thrashing)
    - der compiler kann einige Aufrufe inlinen und einige nicht, je nachdem, wie es für seine Optimierung am besten ist
    - bei macros wird stupide ersetzt ( ++a einem macro zu übergeben führt sehr wahrscheinlich zu einem fehler)


  • Mod

    Bacid90210 schrieb:

    •Inline Funktionen benötigen weniger Zeit für call und return

    Nein, das ist bei Makros und inline-Funktionen so

    •Rekursion stellt Makroprozessor vor Problem welches er nicht lösen kann -> Inline Funktionen unterstützen Rekursion ..

    Ein eher exotischer Vorteil, aber ja.

    Was mich aber wundert ist, dass du die Hauptvorteile von Inline vs Makro nicht genannte hast:
    -Typsicherheit
    -Konsistente Syntax zu anderen Sprachkonstrukten
    -Keine versteckten Kosten (Ausdrücke die man einem Makro als Parameter mitgibt, werden bei jedem Vorkommen im Makro erneut ausgewertet)
    -Korollar: Makroparameter mit Seiteneffekten enden ganz böse
    -Makros funktionieren nicht überall so wie eine Funktion sich verhalten würde. Man muss sehr genau aufpassen (if-else-Blöcke, Klammern,...)

    Das sind die wichtigsten. Kleiner Vorteil noch: Inline ist nur ein Ratschlag für den Compiler. Wenn er meint, dass du Mist baust (und dann hat er meistens Recht), übergeht er das inline. Bei Makros geht das nicht.





  • Ok ...danke Leute das hilft mir schon mal weiter ...


  • Mod

    Oh, ein ganz wichtigen Vorteil von inline-Funktionen gegenüber Makros habe ich noch vergessen:

    Makros zu Debuggen ist die Hölle. Makrofunktionen kann man im Debugger nicht vernünftig schrittweise durchgehen und Breakpoints funktionieren nicht. Dies alleine rechtfertigt schon den Einsatz von Inline, wann immer es möglich ist. Einige Debugger kommen zwar auch mit Makros zurecht, aber das bei weitem nicht so gut wie das Debuggen von normalem Code.

    Noch schlimmer sind verschachtelte Makros. Verschachtelte Funktionen sind so trivial, dass man sich gar nicht mal bewusst ist, dass man es da zu Problemen kommen kann. Aber einen Präprozessor-Syntaxfehler bei verschachtelten Makroaufrufen zu finden ist sehr harte Arbeit.

    Deshalb sollte man Makros wirklich nur da verwenden, wo sie gebraucht werden(man sehe sich Präprozessorbibliotheken an um zu sehen, wozu man Makros nutzen kann) und nicht als schlechten Ersatz für schon vorhandene Sprachkonstrukte.

    edit: Wobei es mich sowieso wundert, dass es solch eines Sprachkonstrukts überhaupt bedarf. Genauso wie register. Inline und register sind rein technische Sachen, die eigentlich überhaupt nichts mit der Funktion des Porgramms zu tun haben (außer dass inline die Funktion auf die aktuelle Übersetzungseinheit beschränkt, aber das ist nur ein Nebeneffekt, wofür eigentlich static da wäre). Ich weiß nicht, was so etwas in einer Sprache zu suchen hat, die unabhängig von der Hardware sein will.



  • Bacid90210 schrieb:

    Inline Funktionen unterstützen Rekursion..

    Rekursion führt aber relativ schnell dazu, dass eine Funktion vom Compiler nicht mehr inline gemacht werden kann. Unrolling von rekursiven Funktionsaufrufen ist nur begrenzt möglich (Tail Recursion).



  • #include <iostream>
    
    // Macro
    #define MACRO_MULTIPLY2(a, b) a * b
    #define MACRO_MULTIPLY3(a, b, c) MACRO_MULTIPLY2(a, b) * c
    
    // Inline
    inline int Multiply2(int a, int b) { return a * b; }
    inline int Multiply3(int a, int b, int c) { return Multiply2(a, b) * c; }
    
    // Terms
    #define TERM1 100 + 4 * 10
    #define TERM2 61 - 1
    #define TERM3 12 - 3 + 5
    
    int main()
    {
    	std::cout << "Macro: " << MACRO_MULTIPLY2(TERM1, TERM2) << std::endl;
    	std::cout << "Inline: " << Multiply2(TERM1, TERM2) << "\n" << std::endl;
    
    	std::cout << "Macro: " << MACRO_MULTIPLY3(TERM1, TERM2, TERM3) << std::endl;
    	std::cout << "Inline: " <<  Multiply3(TERM1, TERM2, TERM3) << std::endl;
    
    	return 0;
    }
    

    Macro fail.



  • ..... schrieb:

    Macro fail.

    Wie schön das du kaputte Macros für einne Vergleich heranziehst. Dieses Beispiel zeigt nur, dass ein Noob leicht fehlerhafte Macros schreiben kann.



  • Janjan schrieb:

    ..... schrieb:

    Macro fail.

    Wie schön das du kaputte Macros für einne Vergleich heranziehst. Dieses Beispiel zeigt nur, dass ein Noob leicht fehlerhafte Macros schreiben kann.

    Ich bin mir des Fehlers bewusst (Fehlende Klammerung). Ich wollte nur vor dem leichtfertigem Gebrauch warnen. Und das ist mir ja anscheinden gelungen 🤡



  • Makros liegen auch immer im global scope und lassen sich nicht in Namespaces einbetten. Wurde bisher noch nicht erwähnt, glaube ich.



  • asc schrieb:

    // Ungetestet:
    #define MAX(a, b) a > b ? a : b
    
    int main()
    {
      int a = MAX(1, 2);
      int b = MAX(++a, 3); => Teste mal was heraus kommt... (Tip: 3 ist es nicht)
    }
    

    hmm...
    Mein Compiler sagt aber 3 🙄

    Aber schon klar, dass du ++a zweimal ausgeführt haben wolltest 😉

    z.B.

    #define MAX(a, b) a >= b ? a : b
    


  • CSpille schrieb:

    Mein Compiler sagt aber 3 🙄

    Gratuliere! Du hast so eben "undefined behaviour" entdeckt! Dies kann sich von Compiler zu Compiler unterscheiden.

    CSpille schrieb:

    #define MAX(a, b) a >= b ? a : b
    

    Immernoch kaputt.



  • Janjan schrieb:

    CSpille schrieb:

    Mein Compiler sagt aber 3 🙄

    Gratuliere! Du hast so eben "undefined behaviour" entdeckt! Dies kann sich von Compiler zu Compiler unterscheiden.

    CSpille schrieb:

    #define MAX(a, b) a >= b ? a : b
    

    Immernoch kaputt.

    Vielen Dank Janjan!

    Dass

    std::cout << (++a >= b ? ++a : b) << std::endl;
    

    undefiniertes Verhalten verursacht, ist mir auch klar...

    Die Intention von asc, war es aber wohl zu zeigen, dass dort (bei den meisten Compilern?)
    wegen einfacher Textersetzung 4 rauskommt, ansonsten habe ich seinen Beitrag fehlinterpretiert.



  • CSpille schrieb:

    Dass
    std::cout << (++a >= b ? ++a : b) << std::endl;
    undefiniertes Verhalten verursacht, ist mir auch klar...

    Da irrt ihr Euch (Du und Janjan). Das Verhalten ist hier wohldefiniert. Der ternäre Operator garantiert eine Ordnung. Das Fragezeichen ist sozusagen ein Sequenzpunkt. Was links davon steht, wird komplett ausgewertet (inklusive Erhöhen von a) bevor genau ein Teil der rechten Seite ausgewertet wird.

    Ähnliche Garantien gibt es bei && , || und dem Sequenzoperator , -- sofern es sich nicht um benutzerdefinierte Funktionen (überladene Operatoren) handelt.

    kk



  • Inline Funktionen benötigen weniger Zeit für call und return

    Inline ist ein Hinweis, es gibt keine Garantien. Auch hat inline genug Nachteile. Z.B. zerstoert Kapselnung, weil im Header definiert.



  • CSpille schrieb:

    asc schrieb:

    // Ungetestet:
    #define MAX(a, b) a > b ? a : b
    
    int main()
    {
      int a = MAX(1, 2);
      int b = MAX(++a, 3); => Teste mal was heraus kommt... (Tip: 3 ist es nicht)
    }
    

    hmm...
    Mein Compiler sagt aber 3 🙄

    Genau das ist auch zu erwarten.

    kk



  • knivil schrieb:

    Inline ist ein Hinweis, es gibt keine Garantien. Auch hat inline genug Nachteile. Z.B. zerstoert Kapselnung, weil im Header definiert.

    Ging es nicht um den Vergleich inline-Funktion <-> Makro? Gegenüber Makros bieten inline-Funktionen keine Nachteile bzgl Kapselung, oder? Ist doch eher umgekehrt.

    kk


Anmelden zum Antworten