Adresse einer Funktion in einer Variable Speichern



  • hoi wie kann ich die Adresse der Funktion int f(); in eine Variable abspeichern?
    Alles was ich bisher versucht habe um die Adresse zu Speichern schlug fehl. 😞

    #include <fstream>
    #include <iostream>
    using namespace std;
    
    int f();
    
    int main() 
    { 
    
    cout<< "adresse von f: " << &f << endl; // Gibt aus: 004011B0
    
    system("PAUSE"); 
    }
    
    int f()
    {
    	cout<<"ok";
    	return 1;
    }
    


  • #include <functional> // C++11
    
    int foo(int a)
    {
    }
    
    int main()
    {
      int (*f2)(int) = &foo;
      auto f3 = &foo; // C++11, automatische Typdeduktion
      std::function<int(int)> f4 = &foo; // C++11
    }
    


  • Mit nem Funktionszeiger.

    int (*funktionszeiger)() = &f;
    std::cout << &funktionszeiger;
    

    Genaueres siehe http://www.willemer.de/informatik/cpp/fktzgr.htm oder sowas.

    Aber wofür brauchste das überhaupt?

    Edit: Zu langsam 😞


  • Mod

    Google mal: Funktionszeiger/function pointer

    #include <iostream>
    using namespace std;
    
    int f();
    
    int main()
    {
      int (*ptr)();  // Pointer auf eine Funktion mit Rückgabewert int und ohne Argumente
    
      cout<< "adresse von f: " << reinterpret_cast<void*>(&f) << endl; 
      ptr = &f;   // Zuweisen so
      cout<< "wert von ptr: " << reinterpret_cast<void*>(ptr) << endl; 
      ptr = f;    // Oder auch so
      cout<< "wert von ptr: " << reinterpret_cast<void*>(ptr) << endl; 
    
      f();
      ptr();      // Und auch beim Aufruf muss man nicht unbedingt dereferenzieren
      (*ptr)();   // Darf man aber
    }
    
    int f()
    {
        cout<<"ok\n";
        return 1;
    }
    
    cout<< "adresse von f: " << &f << endl; // Gibt aus: 004011B0
    

    Das ist komisch. Das sollte eigentlich 1 ausgeben, keine Adresse. Dachte ich zumindest. Ich muss mal tief im Standard wühlen, ob dieses Verhalten legal ist.

    edit: Doppelt zu langsam



  • Incocnito schrieb:

    int (*funktionszeiger)() = &f;
    std::cout << &funktionszeiger;
    

    Das gibt doch die Adresse des Funktionszeigers aus, oder etwa nicht?

    Edit: Anscheinend doch nicht. Das hat irgendwas mit dem von SeppJ genannten zu tun:

    http://ideone.com/U4kRH


  • Mod

    Hacker schrieb:

    Das gibt doch die Adresse des Funktionszeigers aus, oder etwa nicht?

    Richtig. Und std::cout << funktionszeiger; sollte eigentlich 0 oder 1 ausgeben (je nach Wert des Zeigers), keine Adresse, da Funktionszeiger nicht in void* konvertierbar sind und der Operator << nur für diese eine Überladung hat. Die einzige Konvertierung die hier in Frage kommt ist daher eigentlich nach bool.

    Daher frage ich mich, mit welchem Compiler der Threadersteller mit seinem Code die genannte Ausgabe erzeugt hat.



  • Es sollte definitiv die Konvertierung nach bool ausgewählt werden.



  • @SeppJ
    Ich hatte den Borland 5.5 Compiler benutzt.

    Das was mir hier: reinterpret_cast<void*>(ptr); ausgeben wird das würde ich gerne in einer normalen int Variable speichern.

    Ich habe schon überlegt die Ausgabe in einer Datei zu speichern, danach auszulesen und mit stringstream in einer int Variable zu speichern. Aber ich will wissen wie es ohne Datei geht.

    int var = reinterpret_cast<void*>(ptr); mag der Compiler nicht.^^

    #include <iostream>
    using namespace std;
    
    int f();
    
    int main(int argc, char* argv[])
    {
    char a;
    int *var=0;
    
    cout<<"addr: "<< &f << endl;
    
    var = reinterpret_cast<int*>(f);
    
    var+=1;  // Die Variable wird immer um 4 erhöht anstatt um 1 wegen dem int
    	 // ich will aber nur um 1 erhöhen ... 
            // Oder bietet C++ so eine Funktion gar nicht an?
    
    cout<<var<<endl;
    
    system("PAUSE");
    return 0;
    }
    //---------------------------------------------------------------------------
    
    int f()
    {
    	cout<<"ok";
    	return 1;
    }
    


  • Wieso, funktioniert

    int var = reinterpret_cast<int>(ptr);
    

    ?



  • Funktioniert nicht. 🤡

    int var = reinterpret_cast<int>(ptr);
    

    So funktioniert es:

    int * var = reinterpret_cast<int>(ptr);
    

    Ich hab das ganze jetzt mit Inline Assembler gelöst:

    #include <iostream>
    #include <windows.h>
    using namespace std;
    
    int f();
    
    int main(int argc, char* argv[])
    {
    
    int (*var)() = &f;
    unsigned addr;
    
    _asm
    {
    	mov eax, dword ptr [var]
    	mov addr,eax
    }
    
    cout<< hex << addr <<endl; // Gibt 00401378 aus
    
    f();
    
    system("PAUSE");
    return 0;
    }
    //---------------------------------------------------------------------------
    
    int f()
    {
    	cout<<"ok";
    	return 1;
    }
    

  • Mod

    Ich hab das ganze jetzt mit Inline Assembler gelöst:

    Und ist bestimmt falsch. Was glaubst du wohl, wieso das mit einem reinterpret_cast nicht ging, mit dem man ansonsten einen Compiler zu allem zwingen kann, was irgendwie möglich ist?

    P.S.: Borland 5.5? Schreibst du auch mit Hammer und Meißel auf Steintafeln? Kein Wunder, dass der so komische Ausgaben macht, der hat seine Wurzeln ja noch tief in Vorstandardzeiten.



  • Ich habs nochmal mit: CodeGear C++ 5.90

    Gemacht aber wieso soll das falsch sein was ich gemacht habe?
    Es funktioniert alles so wie ich es mir vorgestellt habe.

    Ich hab die Adressen auch nochmal Olly überprüft.


  • Mod

    Dann hast du ziemliches Glück. Auf der Mehrzahl aller Systeme ist ein int kleiner als ein Pointer. In den Lösungen die dir vorgemacht wurde, waren die Casts von Funktionszeiger zu void-Zeiger waren ja schon gewagt (sollten in der Regel aber funktionieren und anders geht's auch gar nicht). Aber das Umwandeln nach int ist nun wirklich total unportabel.



  • Ob es die Mehrzahl ist, darauf würde ich mich nicht festlegen. Aber int ist üblicherweise 4 Byte groß. Unter 32-Bit Systemen sind Zeiger ebenfalls 4 Byte groß, unter 64-Bit Systemen allerdings 8.



  • _asm 
    { 
        mov eax, dword ptr [var] 
        mov addr,eax 
    }
    

    Was passiert mit dem Wert, der vorher in eax enthalten ist?



  • SeppJ schrieb:

    Richtig. Und std::cout << funktionszeiger; sollte eigentlich 0 oder 1 ausgeben (je nach Wert des Zeigers), keine Adresse, da Funktionszeiger nicht in void* konvertierbar sind

    Was die C++-Streams mit einem Funktionszeiger machen sollten, weiß ich nicht, aber wieso sollten Funktionszeiger nicht implizit nach void* konvertierbar sein? Das gilt vielleicht für Methodenzeiger, weil die mehr können als nur auf eine Speicherstelle zu verweisen, aber ein Funktionszeiger ist tatsächlich nur ein blanker Zeiger.

    Zumindest meine Compiler (C++Builder, Visual C++) haben mit Funktionszeiger -> void* auch keine Probleme.



  • knivil schrieb:

    _asm 
    { 
        mov eax, dword ptr [var] 
        mov addr,eax 
    }
    

    Was passiert mit dem Wert, der vorher in eax enthalten ist?

    push, pop und gut is



  • Edit²³: Hab übersehen, dass reinterpret_cast hier eher unerwünscht ist. Aber man kann ja mit sizeof() eine größenabfrage machen und was hinbasteln.



  • knivil schrieb:

    _asm 
     { 
         mov eax, dword ptr [var] 
         mov addr,eax 
     }
    

    Was passiert mit dem Wert, der vorher in eax enthalten ist?

    Der Wert der vorher in eax war wird einfach überschrieben.

    Auf 32Bit systemen funktioniert das Programm anscheind gut. (Getestet auf Win XP 32Bit und Win7 32Bit) Dumm das man 64Bit System im moment defekt ist ... Aber wenn das wieder rdy ist dann teste ich es dort auch mal.



  • audacia schrieb:

    Was die C++-Streams mit einem Funktionszeiger machen sollten, weiß ich nicht, aber wieso sollten Funktionszeiger nicht implizit nach void* konvertierbar sein?

    Erinnerst du dich an die Speichermodelle unter DOS? Tiny, Small, Medium, Compact, Large, Huge? Da gab es Fälle, in denen Daten mit near-Zeigern und Code mit far-Zeigern oder umgekehrt adressiert wurden. Der Standard ermöglicht sowas, indem er keine Umwandlung zwischen Daten- und Funktionszeigern vorsieht.


Anmelden zum Antworten