Adresse einer Funktion in einer Variable Speichern


  • 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.



  • Zu dem Problem mit der Zeigergröße:

    #include <boost/integer.hpp>
    
    int main() {
        typedef boost::int_t<sizeof(void*)>::least address;
    }
    

  • Mod

    pyhax schrieb:

    Zu dem Problem mit der Zeigergröße:

    #include <boost/integer.hpp>
    
    int main() {
        typedef boost::int_t<sizeof(void*)>::least address;
    }
    

    Das kann ich (offiziell erst in C++11, aber das sollten auch sonst schon viele Compiler können, die eine C99-Standardbibliothek dabei haben) einfacher:

    #include <cinttypes>
    
    std::intptr_t address;
    


  • SeppJ schrieb:

    Das kann ich (offiziell erst in C++11, aber das sollten auch sonst schon viele Compiler können, die eine C99-Standardbibliothek dabei haben) einfacher:

    #include <cinttypes>
    
    std::intptr_t address;
    

    👍

    Das kannte ich noch nicht.



  • Bashar schrieb:

    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.

    Ja, kenne ich gut.

    Bashar schrieb:

    Der Standard ermöglicht sowas, indem er keine Umwandlung zwischen Daten- und Funktionszeigern vorsieht.

    Verstehe ich nicht. Es ist grundsätzlich eine Umwandlung eines near-Zeigers in einen far-Zeiger möglich, andersherum aber nicht. Also wäre auch ein far-Funktionszeiger nicht in void*, sondern nur in void far* umwandelbar. Aber wo ist der Zusammenhang zwischen Speichermodellen, die verschiedene Zeigerbreiten unterstützen, und der Umwandlung von Funktions- nach Datenzeigern? Das sind doch völlig orthogonale Kriterien.

    *Edit:*Ich glaube, bei x86 werden near-Datenzeiger über DS adressiert, near-Funktionszeiger allerdings über CS, so daß sie nicht austauschbar sind. Vielleicht meinst du das?

    Edit 2: werden werden werden



  • Gibts near- und far Zeiger eigentlich noch unter x64 Systemen?


Anmelden zum Antworten