Adresse einer Funktion in einer Variable Speichern
-
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; }
-
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.
-
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 sindWas 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; }
-
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?
-
314159265358979__ schrieb:
Gibts near- und far Zeiger eigentlich noch unter x64 Systemen?
Schon nicht mehr auf einigen (modernen) 32-Bit Systemen. Bei entsprechenden 32/64-Bit Systemen herrscht eine lineare Speicherverwaltung, wobei jeder Pointer auf jede x-beliebige Speicherzelle zeigen kann.
-
Jein. Die Segmentregister sind nach wie vor vorhanden, aber im Long-Mode werden sie nicht mehr zur Segmentierung verwendet (das war ja auch im 32-Bit-Protected-Mode schon unüblich, wäre aber noch gegangen). Einige werden komplett abgeschaltet, ein paar können aus Kompatibilitätsgründen noch benutzt werden (Zwischenzeitlich hat man einigenorts die Segmentregister, die man zur Segmentierung nicht mehr brauchte, für andere Zwecke missbraucht, unter Windows beispielsweise als Verweis auf threadlokale Daten).
Near- und Far-Pointer a la 16-Bit-Real-Mode kann man im long mode nicht mehr betreiben, es hindert einen aber nichts daran, in andere Modi zu wechseln. Jedenfalls, wenn man ausreichend masochistisch veranlagt ist.
-
audacia schrieb:
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.
Ja richtig, Funktionszeiger können dann nicht sinnvoll nach void* umgewandelt werden. void far* gibts im Standard nicht.
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.
Es geht ja auch nicht ums Unterstützen. Wenn deine Funktionszeiger grundsätzlich far sind und deine Datenzeiger grundsätzlich near (IIRC Speichermodell Medium), dann kannst du sie nicht sinnvoll ineinander umwandeln.
*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?
Das meinte ich eigentlich nicht, aber das ist ja ein ähnlich gelagertes Problem.
-
Bashar schrieb:
Es geht ja auch nicht ums Unterstützen. Wenn deine Funktionszeiger grundsätzlich far sind und deine Datenzeiger grundsätzlich near (IIRC Speichermodell Medium), dann kannst du sie nicht sinnvoll ineinander umwandeln.
Stimmt, das ist ein Argument.
seldon schrieb:
(Zwischenzeitlich hat man einigenorts die Segmentregister, die man zur Segmentierung nicht mehr brauchte, für andere Zwecke missbraucht, unter Windows beispielsweise als Verweis auf threadlokale Daten).
Oder auch SEH unter 32-Bit-Windows. Dort ist FS:[0] stets der Verweis auf den Anfang der Liste der Exception-Handler.
seldon schrieb:
es hindert einen aber nichts daran, in andere Modi zu wechseln
Das gilt natürlich nur, wenn du Betriebssystem bist. Ring 3 wird dich mit allen Kräften daran hindern, in den Real Mode zu wechseln.