reinterpret_cast wann definiert?



  • Hallöchen,

    Ich habe schon ab und zu Code gesehen, der einen vector<uint8_t> als uint32_t* anspricht, um gewisse Operationen auf ganzen 32-Bit-Ints auszuführen. Das funktioniert in der Realität immer, aber darf man das auch strikt nach Standard gesehen?

    Falls nicht, könnt ihr euch Fälle vorstellen, wo das nicht funktioniert?



  • Reininterpretiererverein schrieb:

    Ich habe schon ab und zu Code gesehen, der einen vector<uint8_t> als uint32_t* anspricht, um gewisse Operationen auf ganzen 32-Bit-Ints auszuführen. Das funktioniert in der Realität immer,

    Das funktioniert nie! Du meinst vielleicht den "Inhalt", also data oder die Adresse des ersten Elements.



  • Nein, da gibt's zwei wundertolle Regeln im Standard, "strict aliasing" und "alignment". Das sind einmal:

    3.10/10 schrieb:

    If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
    — the dynamic type of the object,
    — a cv-qualified version of the dynamic type of the object,
    — a type similar (as defined in 4.4) to the dynamic type of the object,
    — a type that is the signed or unsigned type corresponding to the dynamic type of the object,
    — a type that is the signed or unsigned type corresponding to a cv-qualified ersion of the dynamic type of the object,
    — an aggregate or union type that includes one of the aforementioned types among its elements or nonstatic data members (including, recursively, an element or non-static data member of a subaggregate or contained union),
    — a type that is a (possibly cv-qualified) base class type of the dynamic type of the object,
    — a char or unsigned char type.

    und einmal 3.11. Und diese Regeln sind durchaus auch nicht zu misachten, "das funktioniert in der Realität immer" ist nur für x86 und VS klar. Andere Prozessoren können u.U. gar keine 32 bit words aus nicht durch 4 teilbaren Adressen lesen (uint8_t's können aber auf solchen Adressen liegen), und andere Compiler optimieren vielleicht unter Annahme von strict aliasing.

    Es gibt allerdings eine einfache Möglichkeit uint32_t's portabel aus Bytes zu lesen, die da wäre:

    uint8_t buf[4] = {0, 1, 2, 4};
    uint32_t i;
    memcpy(&i, buf, sizeof i);
    

    Das ist auch nicht langsamer, das memcpy wird komplett wegoptimiert und dieser Code erzeugt das gleiche binary:

    uint8_t buf[4] = {0, 1, 2, 4};
    uint32_t i = *reinterpret_cast<uint32_t*>(buf);
    

  • Mod

    die da wäre:

    Wo steht, dass man einfach irgendein char -Array reinkopieren darf? Es ist doch gegeben, dass man zuerst das Objekt in das char -Array kopiert, und dann erst das char -Array zurück in das Objekt kopieren darf.

    Oder irre ich mich da?



  • Arcoth schrieb:

    die da wäre:

    Wo steht, dass man einfach irgendein char -Array reinkopieren darf? Es ist doch gegeben, dass man zuerst das Objekt in das char -Array kopiert, und dann erst das char -Array zurück in das Objekt kopieren darf.

    Oder irre ich mich da?

    Man darf alle PODs char -weise manipulieren wie man lustig ist. Nur das exakte Ergebnis ist implementationsdefiniert. Deswegen ist das selten eine gute Idee, aber verboten ist es nicht.

    Kann sein, dass das Kopieren von ungültigen Zeigern, die auf diese Weise erzeugt wurden, UB ist.



  • @Arcoth
    Ich bin mir zu 99% sicher dass das so wie cooky451 es geschrieben hat OK ist. Warum sollte es das nicht sein? Ich darf ja sogar ein beliebiges Objekt (beliebiger Typ!) jederzeit mittels einen char-Zeigers überschreiben.

    @cooky451
    So lange uint8_t als char oder unsigned char definiert ist, ist strict aliasing kein Thema. EDIT: <== Unsinn /EDIT



  • hustbaer schrieb:

    @cooky451
    So lange uint8_t als char oder unsigned char definiert ist, ist strict aliasing kein Thema.

    Ne, das ist nur in die eine Richtung der Fall. Hätte der TE geschrieben dass sie auf einen vector<uint32_t> mit uint8_t* zugreifen, dann wäre strict aliasing kein Problem (alignment natürlich auch nicht), anders rum aber sehr wohl.



  • @cooky451
    Wie willst du die beiden Richtungen unterscheiden?

    EDIT: OK, vergiss die Frage.
    Ja, als uint32_t lesen könnte problematisch werden. Schreiben müsste mMn. OK sein.


Anmelden zum Antworten