static_cast<char*>(static_cast<void*>(&pod)) vs. reinterpret_cast<char*>(&pod)



  • @Icematrix,
    Kannst du das auch beweisen? Womöglich mit dem C++ Standard? Kapitel, Absatz? Oder ist es einfach nur deine Vermutung?

    Grüssli

    Reine Logik, ich habe mehr mit dem Kompiliat eines C++-Compilers zu tun, also dem ASM-Code, als mit normalem C++-Code.

    Ansonsten, das steht in jedem Lehrbuch, dass der reinterpret_cast einfach nur das Bytemuster neu interpretiert, um den Compiler zu Sachen zu zwingen, die seine Typsicherheit verbietet.

    Im Endeffekt ist es total egal, ob eine Addresse in einem unsigned long oder in einem char* oder einem FooBarClass& ist, für den Compiler sind das alles nur vorzeichenlose Integer, die groß genug sind, eine Speicheraddresse zu halten.



  • Icematix schrieb:

    [...]

    Wenn man den Zeiger nach dem Cast noch benutzen will, ist das so falsch.



  • Wenn man den Zeiger nach dem Cast noch benutzen will, ist das so falsch.

    Möchtest du genauer erläutern, wie du das meinst?
    Solange du auf ASM-Ebene "legal" bleibst, kannst du den C++-Compiler zu den ekligsten Sachen zwingen 😉


  • Administrator

    Tachyon schrieb:

    Es geht also, es sei denn, T1 ist durch das Alignment nicht auf T2 abbildbar.

    Wie du aus dem Abschnitt schliesst, dass es gehen soll, ist mir rätselhaft. Kannst du das mal näher erläutern und vielleicht übersetzen, wie du dies verstehst?

    Tachyon schrieb:

    Das gleiche Problem gibt es auch beim Umweg über void* (und zwar an der Stelle, an der void void* auf T* gecastet wird).

    Nein, da gibt es keine Probleme. Beim Cast von void* auf T* ist T char . Und dafür gibt es eben: 3.9.2 Absatz 4.

    @Icematix,
    Es geht hier aber darum, was der Standard sagt, und nicht was ein Kompiler liefert oder ein Lehrbuch sagt. Hustbaer interessiert sich für die Aussage dazu vom Standard:

    hustbaer schrieb:

    Mir geht es hier mal nur um das Casten des Zeigers. Und auch nicht darum was funktioniert (ich weiss dass beides funktioniert), sondern darum was der Standard sagt.

    Grüssli



  • Wegen Falschaussage selbst entfernt.



  • Diskussionen darüber was alles geht und was übliche Compiler wie machen interessieren mich hier gar nicht. Das weiss ich nämlich alles hübsch selbst.

    Mich interessiert was der Standard vorschreibt.

    Ich hätte mir auch gedacht dass das klar aus meinem Beitrag hervorgeht. Demzufolge halte ich einige Beiträge hier auch für ziemlich unpassend.

    Tachyon schrieb:

    ISO/IEC 14882:2003 5.2.10 §7 schrieb:

    A pointer to an object can be explicitly converted to a pointer to an object of different type.

    Except that converting an rvalue of type “pointer to T1” to the type “pointer to T2” (where T1 and T2 are object types and where the alignment requirements of T2 are no stricter than those of T1) and back to its original type
    yields the original pointer value, the result of such a pointer conversion is unspecified.

    Es geht also, es sei denn, T1 ist durch das Alignment nicht auf T2 abbildbar. Das gleiche Problem gibt es auch beim Umweg über void* (und zwar an der Stelle, an der void void* auf T* gecastet wird).
    Die Rückkonvertierung ist ebenfalls nicht spezifiziert, da POD* höchstwahrscheinlich strengere Alignment-Anforderungen hat als char*
    Passt also.

    In dem Absatz steht ganz was anderes. Lies ihn noch ein paar mal, vielleicht wird's dann klar.
    Da steht dass das Ergebnis der Konvertierung von T1 nach T2 "unspecified" ist.(Die Konvertierung selbst ist erlaubt, aber der Standard definiert hier nicht wie das Ergebnis auszusehen hat)

    Lediglich wenn man wieder zurück-konvertiert, also T1 -> T2 -> T1, dann muss am Ende wieder das rauskommen mit dem man angefangen hat. Vorausgesetzt dass T2 keine "strengeren" Alignment-Vorgaben hat als T1.

    Also genau andersrum. BTW: speziell dass man von void* wieder zu T zurückcasten darf, wenn der void* aus einem T* "gewonnen" wurde, sollte auch hinlänglich bekannt sein.

    @Icematix:
    Auf Plattformen mit "flacher" Adressierung sind die meisten Dinge recht einfach, ja.
    Der Standard erlaubt allerdings durchaus Plattformen wo Zeiger auf verschiedene Typen unterschiedlich gross sind. Oder einfach nur unterschiedlich zusammengesetzt.
    Dort könnte ein reinterpret_cast dann gar nicht als "Bitmuster anders interpretieren" implementiert sein, da das Bitmuster in der Länge nicht passt.
    Tjo.



  • hustbaer schrieb:

    [...]

    Du hast recht. Asche über mein Haupt. Irgendwie hat mich der eingeschobene Klammersetz durcheinander gebracht.
    Es ist erlaubt, aber unspezifiziert... Ich hasse den Standard.



  • @Icematix:
    Auf Plattformen mit "flacher" Adressierung sind die meisten Dinge recht einfach, ja.
    Der Standard erlaubt allerdings durchaus Plattformen wo Zeiger auf verschiedene Typen unterschiedlich gross sind. Oder einfach nur unterschiedlich zusammengesetzt.
    Dort könnte ein reinterpret_cast dann gar nicht als "Bitmuster anders interpretieren" implementiert sein, da das Bitmuster in der Länge nicht passt.
    Tjo.

    Dann benutz dafür den static_cast, wenn du eine intelligente Umwandlung brauchst?

    Der reinterpret_cast macht seinen Dienst, wird dir eben nicht das korrekte Ergebnis liefern.
    So würde zb auf meiner x86-Kiste

    unsigned int32 var32 = 0xABCDEF00;
    unsigned int16 var16 = reinterpret_cast<unsigned int16>(var32);
    

    var16 0x00EF enthalten während sie bei einem static_cast overflowen würde.



  • Tachyon schrieb:

    hustbaer schrieb:

    [...]

    Du hast recht. Asche über mein Haupt. Irgendwie hat mich der eingeschobene Klammersetz durcheinander gebracht.
    Es ist erlaubt, aber unspezifiziert... Ich hasse den Standard.

    Naja, der Absatz ist auch eine Glanzleistung an "unverständlich formuliert". Ich hab den Satz auch mehr als 2x lesen müssen um zu verstehen was das jetzt heissen soll. (Zumindest glaube ich dass ich es richtig verstanden habe :D)


  • Mod

    Icematix schrieb:

    Der reinterpret_cast macht seinen Dienst, wird dir eben nicht das korrekte Ergebnis liefern.
    So würde zb auf meiner x86-Kiste

    unsigned int32 var32 = 0xABCDEF00;
    unsigned int16 var16 = reinterpret_cast<unsigned int16>(var32);
    

    var16 0x00EF enthalten während sie bei einem static_cast overflowen würde.

    Also mein Compiler weigert sich, das überhaupt zu kompilieren.

    Ein Blick in Defining reinterpret_cast for pointer types kann zur Klarstellung dienen.
    Im Übrigen bin ich der Ansicht, dass diese Änderung nicht notwendig ist, denn diese Klarstellung ist im Grunde schon in 5.2.10/10 angelegt (abgesehen vom Fall, das von oder zu cv void oder Nullpointer gecastet werden).

    An lvalue expression of type T1 can be cast to the type “reference to T2” if an expression of type “pointer to T1” can be explicitly converted to the type “pointer to T2” using a reinterpret_cast. That is, a reference cast reinterpret_cast<T&>(x) has the same effect as the conversion *reinterpret_cast<T*>(&x) with the built-in & and * operators. The result is an lvalue that refers to the same object as the source lvalue, but with a different type. No temporary is created, no copy is made, and constructors (12.1) or conversion functions (12.3) are not called.67)

    In allen Fällen in denen wir einen denen wir einen dereferenzierbaren Zeiger haben, bestimmt dieser Abschnitt das Ergebnis sowohl eines Refernmz- als auch eine Pointercasts.


Anmelden zum Antworten