Adresse einer Funktion



  • Gugelmoser schrieb:

    fr33g schrieb:

    Da versteht dann der GCC wohl was falsch oder?

    Ist es nicht vielmehr so, dass der MSVC irgendwas anderes macht. Wenn der Standard keine passende, überladene ostream::operator<< Funktion bietet, wie soll dann eine aufgerunfen werden? Ich finde das Verhalten vom GCC absolut nachvollziehbar.

    Jetzt war mein Post wieder zu langsam...ich meinem letzen Post habe ich dir ja zugestimmt;-)

    Aber was ist denn jetzt eg wegen dem inline und wie kann es eg kommen, dass der MVSC was macht, was eg nicht so vom Standard vorgesehen ist?

    Lg freeG



  • fr33g schrieb:

    ... reinterpret_cast zu void* caste, kommt auch bei allen 4 Versionen die gleiche Speicheradresse heraus.

    Ok, mittels reinterpret_cast. Aber wir wissen ja, dass der reinterpret_cast wirklich alles mögliche hin und her biegen kann. 😉

    fr33g schrieb:

    Beim MVSC geht es allerdings ohne zu casten, hat er dann weiter überladene <<-Operatoren überladen oder wieso geht es dort?

    Hmm, weiß ich nun auch nicht. Müssen wir mal warten, ob die Profis nachher kurz etwas dazu sagen. 🙂



  • Hoffentlich, weil das interessiert mich jetzt schon 😉

    Außerdem würde mich auch wie gesagt interessieren, wie das bei Inline-Funktionen ist, ob die also wirklich auch im Arbeitsspeicher untergebracht werden.

    Lg freeG



  • fr33g schrieb:

    Außerdem würde mich auch wie gesagt interessieren, wie das bei Inline-Funktionen ist, ob die also wirklich auch im Arbeitsspeicher untergebracht werden.

    Steht eigentlich alles im Effektive C++:

    • inline ist keine zwingende Anweisung, sondern ein Ratschlag. Der Compiler muss sich nicht dran halten.
    • Wenn er es inline macht, dann ist die Funktion nicht im Arbeitsspeicher untergebracht, es sei denn man nimmt ihre Adresse. inline-Funktionen verhalten sich ja wie echte Funktionen.
    • Die anderen Aufrufe werden aber dennoch geinlined
    • Wie immer: So ist es in der Praxis, der Standard garantiert nichts und du kannst dich nicht drauf verlassen. Und wenn man sich auf so etwas verlässt, ist einem wirklich nicht zu helfen 😉


  • keinprofi schrieb:

    inline ist keine zwingende Anweisung, sondern ein Ratschlag. Der Compiler muss sich nicht dran halten.

    Das ist nicht richitg. Der Compiler versucht immer eine Inline-Expansion durchzuführen (wenn es sich lohnt ja, ansonsten nein), egal ob du inline schreibst oder nicht. Das Problem ist (inline schafft dazu dann Abhilfe), dass die Inline-Expansion nur dann durchgeführt werden kann, wenn sich Funktiondefinition und Aufrufstelle in derselben Übersetzungseinheit befinden. Falls dies nicht der Fall ist, kannst du inline benutzen, und ermöglichst somit dem Compiler, dass er die Funktion in einer entsprechenden Header definieren darf.

    Siehe auch FAQ: http://www.c-plusplus.net/forum/105893

    [EDIT] editiert nach davies Hinweis.



  • Gugelmoser schrieb:

    Das ist nicht richitg. Der Compiler versucht immer eine Inline-Expansion durchzuführen (wenn es sich lohnt ja, ansonsten nein), egal ob du inline schreibst oder nicht.

    Wo hab ich das behauptet?

    inline-FAQ schrieb:

    Da es ihm damit auch freigestellt ist, ob er einen Funktionsaufruf inline expandiert, kann es kein Sprachmittel geben, mit dem man dieses Verhalten erzwingen kann

    keinprofi schrieb:

    inline ist keine zwingende Anweisung, sondern ein Ratschlag. Der Compiler muss sich nicht dran halten.



  • keinprofi schrieb:

    inline-FAQ schrieb:

    Da es ihm damit auch freigestellt ist, ob er einen Funktionsaufruf inline expandiert, kann es kein Sprachmittel geben, mit dem man dieses Verhalten erzwingen kann

    keinprofi schrieb:

    inline ist keine zwingende Anweisung, sondern ein Ratschlag. Der Compiler muss sich nicht dran halten.

    Ich glaube du verwechselst hier zwei paar Sachen:
    Dem Compiler ist die Inline-Expansion freigestellt. Wenn es sich lohnt macht er es, wenn nicht dann nicht. Das Keyword inline hat nichts mit der Inline-Expansion zu tun.

    Inline-Expansion = Statt an die Adresse der Funktion zu springen, wird der Code der Funktion an der Aufrufstelle eingefügt.

    Keyword inline = Hey Compiler, ich erlaube dir, dass du die Funktion in der entsprechenden Header definieren darfst, sodass du dann in der Lage bist, eventuell eine Inline-Expansion durchzuführen.

    [EDIT] editiert nach davies Hinweis.



  • Man könnte fast meinen, du würdest glauben, dass folgender Code-Ausschnitt in Ordnung wäre:

    //foo.cpp
    inline void f ()
    {
    }
    
    void foo ()
    {
      f();
    }
    
    //bar.cpp
    inline void f ();
    
    void bar ()
    {
      f();
    }
    


  • außerdem ist auch ein reinterpret_cast hier nicht möglich. sizeof(void*) liefert nämlich nicht garantiert denselben wert wie sizeof(void(*)()). der "beste" weg (der einzige) ist es, den funktionszeiger in einen integralen typ zu konvertieren:

    cout << hex << reinterpret_cast<long>(&fun) << endl;
    

    der compiler sollte dich dann zumindest warnen, falls long zu klein für den zeiger ist, und es ist erlaubt.

    GCC ist zumindest mit dem teil richtig, der den zeiger auf die funktion in einen bool umwandelt, diese konvertierung ist nämlich explizit erlaubt.



  • Vielen Dank Leute, jetzt verstehe ich das ganze.
    Noch eine kurze Frage, bei Templates verhält es sich doch genau so? Wenn ein Template instanziert wird( ich meien jetzt Template-Funktionen) und es nicht geinlint wird, dann schreibt der Compiler ja die entsprechende Version der Funktion und diese kommt dann logischerweise auch in den Arbeitsspeicher oder?

    Lg freeG



  • die jeweilige spezialisierung, natürlich. aber ein bisschen aufpassen musst du in deinen formulierungen. der compiler schreibt die objektdateien, und natürlich erzeugt er code für jede (implizite oder explizite) instanziierung eines funktionstemplates, einmal; (edit: schau dir im standard kapitel 3.2 zur one-definition-rule an) genauso, wie er für jede inline-funktion mit externer linkage nur etwas erzeugt, das sich so verhält, als gäbe es es nur einmal. dir kann, wenn du bei standard c++ bleibst, zuerst mal völlig egal sein, wer was wie erzeugt und was in den arbeitsspeicher wann und wo und wie geladen wird. C++ (03) macht hier sowieso wenige garantien, was reihenfolgen oder so etwas anbelangt. der standard garantiert dir nur, dass von jeder funktion mit externer linkage du jederzeit einen funktionszeiger auf diese funktion bekommen kannst, der über alle übersetzungseinheiten hinweg denselben "wert" haben muss, den du in einen beliebigen anderen funktionszeiger (aber nicht elementfunktionszeiger oder "normalen" zeiger) oder nach bool konvertieren kannst (oder in einen integralen typen, der groß genug ist) und wieder zurück, so dass nach der rückkonvertierung der zeiger wieder auf dasselbe "ding" zeigt.

    aber der standard garantiert dir z.b. nicht einmal folgendes:

    //foo.cpp
    int foo () { return 0; }
    
    //main.cpp
    int foo ();
    
    typedef void (*fun_ptr) ();
    
    int main ()
    {
       fun_ptr ptr = reinterpret_cast<fun_ptr>(foo());
       assert (ptr == 0); 
    }
    

Anmelden zum Antworten