Konvertierung einer Adresse zu einem Zeiger



  • Hallo, ich habe da ein kleines Verständnisproblem, was die Konvertierung einer Adresse in einen Zeiger betrifft. Ich bin durch folgendes Beispiel darauf gestoßen:

    std::ofstream ziel("double.dat", std::ios::binary | std::ios::out);
    
    	double d = 1.1;
    	for (int i = 1; i <= 20; ++i) {
    		ziel.write(reinterpret_cast<const char*>(&d), sizeof(d));
    		d *= 1.1;
    	}
    
    	ziel.close();
    

    Gut, also mir ist so weit klar, dass die Funktion write zwei Parameter verlangt, wobei der erste ein Zeiger auf Konstante Zeichen ist und der zweite die Größe des zu übetragenen Objekts in Byte beansprucht.

    Leider kann ich überhaupt nicht nachvollziehen, was die Anweisung

    reinterpret_cast<const char*>(&d)
    

    überhaupt bewirkt. Das resultierende Objekt scheint ein const char* zu sein, aber in wie weit beeinflusst die Adresse von d das Ganze?


  • Mod

    GurkenglasMitBohnen schrieb:

    Das resultierende Objekt scheint ein const char* zu sein, aber in wie weit beeinflusst die Adresse von d das Ganze?

    Das ist eben die Adresse, auf den der resultierende Zeiger zeigt.

    &d ist ein Zeiger auf d, der ist logischerweise vom Typ Zeiger auf double. Da write aber einen Zeiger auf char verlangt, muss der Typ umgewandelt werden. reinterpret_cast heißt (in den meisten Fällen), dass der Compiler so tun soll, als ob ein Zeiger auf einen anderen Typen zeigt, als der, auf den er eigentlich zeigt.



  • Um ehrlich zu sein hatte ich nicht damit gerechnet, um diese Uhrzeit noch eine Antwort zu bekommen, und dann auch noch vom Guru persönlich 😃

    Also gut, dass &d prinzipiell ein Zeiger auf das double Element ist hat mir geholfen, die Syntax der Umwandlung (double* in const char*) besser zu verstehen.

    Die tatsächliche Wirkung von double* -> const char* bleibt mir leider noch ein Rätsel. Ich habe mir kurz ein kleines Programm dazu geschrieben:

    #include <iostream>
    #define PRINT(X) std::cout << (#X)<<  " = " << (X) << std::endl;
    
    int main(int argc, char** argv) {
    	double d = 1.1;
    	const char* cptr = reinterpret_cast<const char*>(&d);
    	PRINT(cptr);
    	PRINT(*cptr);
    	PRINT(&cptr);
    	PRINT(&d);
    
    	std::system("PAUSE");
    	return 0;
    }
    

    Tut mir wirklich leid, aber ich habe den zweiten Teil deines Beitrags wirklich nicht verstanden.
    Ausgehend von meinem jetzigen Wissensstand müsste cptr == &d sein. Auf der Konsole bekomme ich so etwas wie "ÖÜÜÜÜ|||\" angezeigt.

    Die Dereferenzierung von cptr zeigt mit "Ü" an.

    Etwas besser Vertändlich hingegen waren für mich die Anweisungen
    &cptr und &d welche mir zumindest Adresse anzeigen. Die beiden Adresse &cptr und &d liegen 12 Bytes außeinander. ( Ich denke das hat weniger mit meinem Verständnisproblem zu tun)


  • Mod

    GurkenglasMitBohnen schrieb:

    Ausgehend von meinem jetzigen Wissensstand müsste cptr == &d sein.

    Nun, man kann Pointer verschiedener Typen nicht vergleichen (außer mit nullptr_t), daher werden sie nicht direkt gleich sein. Wenn du dir aber den Zahlenwert anzeigen lässt, dann werden diese in diesem Fall aber tatsächlich gleich sein.

    Auf der Konsole bekomme ich so etwas wie "ÖÜÜÜÜ|||\" angezeigt.

    Du hast einen char* an den ostream::operator<< gegeben. Das heißt, es wurde nicht der Zahlenwert des Zeigers ausgegeben, sondern die Sonderbehandlung zur Ausgabe von Zeichenketten benutzt. Es wurde also so lange ausgegeben was an der Stelle im Speicher steht, bis zufällig auf eine 0 gestoßen wurde.

    cout << reinterpret_cast<const void*>(cptr); wäre eine Möglichkeit, sich den Zahlenwert eines char* ausgeben zu lassen. Bei den meisten anderen Zeigertypen ist solch einer Verrenkung nicht nötig, diese Sonderbehandlung von char* ist auf die historische Art der Zeichenkettenbehandlung in C zurück zu führen.

    Die Dereferenzierung von cptr zeigt mit "Ü" an.

    Das ist dann eben das was an der Stelle in Speicher steht, als Zeichen interpretiert. Die interne Darstellung von 1.1 als double geht (auf herkömmlichen Systemen) mit dem Byte 154 los, das ist auf manchen Windowssystemen der Zeichencode für 'Ü'. Danach folgen 5x 153 ('Ö'), 241 ('±') und 63 ('?'). "ÜÖÖÖÖÖ±?", erinnert dich das an was? Je nachdem, was genau du für eine Codetabelle nutzt, sind es eventuell auch andere Zeichen.

    Etwas besser Vertändlich hingegen waren für mich die Anweisungen
    &cptr und &d welche mir zumindest Adresse anzeigen. Die beiden Adresse &cptr und &d liegen 12 Bytes außeinander. ( Ich denke das hat weniger mit meinem Verständnisproblem zu tun)

    Du hast halt die Adressen der beiden Variablen cptr und d verglichen. Die liegen eben nebeneinander im Speicher. Sind es wirklich 12 Bytes Unterschied? Möglich, aber ich hätte eher 8, eventuell auch 16 erwartet. Denk dran, dass die Ausgabe hexadezimal ist!



  • Stark, endlich hat's klick gemacht!
    Die unterschiedliche Interpretation durch const char* hat mich wirklich sehr verwirrt.

    Im übrigen (nur falls es dich interessiert) ist die Differenz zwischen &d und &cptr tatsächlich 12. Ich meine sogar zwischendurch 16 berechnet zu haben, warscheinlich liegts an der Müdigkeit.

    1. Programmaufruf :
    &cptr = 00F4FD50
    &d = 00F4FD5C
    => 12 Bytes differenz

    In diesem Sinne möchte ich mich für meine schreckliche Rechtschreibung in den frühen Morgenstunden entschuldigen und bedanke mich für die auführliche Hilfe um diese Uhrzeit! 🙂


Anmelden zum Antworten