Frage zu "besonderem" "Hack"



  • IMHo wäre es wirklich etwas sicherer

    return *((int *)_color);
    

    zu schreiben. Aber sicher ist noch gar nichts.
    Es ist nie gesagt, dass ein char genau 255 Werte annehmen kann. Besser (und genauso performant) ist daher, ein Bitfield zu verwenden.

    unsigned int r : 8;
    unsigned int g : 8;
    unsigned int b : 8;
    unsigned int a : 8;
    

    Leider sagt immer noch niemand, dass das hintereinander liegen muss, wenn du sicher sein willst, dass es klappt, musst du in deinem autoconf-Script (oder was du auch immer verwendest) zur Compile-Time testen, ob vier Bytes in einen Integer passen und musst die einzelnen Werte per Bitshifting setzen. Tönt zwar inperformant, aber genau das macht der Compiler intern.

    Jetzt ist die Frage, ob das etwas bringt und wenn du sehr oft auf die r,g,b,a-Werte zugreifst, bringt es effektiv nichts, die Umrechnung zu vereinfachen und zu verschnellern, wenn noch mehr Zeit beim Zugriff auf die Werte verlierst.

    Fazit: Unperformanter Hack, unportabler Hack, schlechter Hack. Eigentlich hat das nicht einmal die Bezeichnung Hack verdient, da der einzige Zweck eine Erleichterung der Lesbarkeit darstellt und Hacks eher andersrum funktionieren.



  • Man hätte hier auch einfach ne Union nehmen können.

    Oder einen int/uint32_t Wert mit Rumshiften erzeugen/zerlegen.

    Das Geshifte optimiert der Compiler im Endeffekt sowieso weg, von daher sollte das auch gleich performant sein.

    Das wäre vermutlich die sauberste Variante.



  • Das ist der Versuch alle 4 Bytes auf einmal zu setzen/lesen. ((int)this) ist äquivalent zu reinterpret_cast<int&>(*this). Der Der this-Zeiger wird einfach als int-Zeiger behandelt. Streng genommen ist das aus drei Gründen nicht erlaubt:
    1. Color ist kein POD
    2. Verletzung von §3.10/15 (Strinct-Aliasing)
    3. Folgendes kann nicht garantiert werden: alignof(Color)>=alignof(int)

    Richtig wär's mit memcpy und memset gewesen:

    void SetRawColor(unsigned color32)
    {
      memcpy(_color,&color32,4);
    }
    
    unsingned GetRawColor() const
    {
      unsigned r;
      memcpy(&r,_color,4);
      return r;
    }
    

    oder alternativ das Speichern als int:

    public:
      void SetRawColor(uint32_t color32)
      { color32_ = color32; }
    
      uint32_t GetRawColor() const
      { return color32_; }
    
      unsigned char& operator[](int idx) {
        // ist nach §3.10/15 erlaubt
        unsigned char* p = reinterpret_cast<unsigned char*>(&color32_);
        return p[idx];
      }
    
      unsigned char operator[](int idx) const {
        // ist nach §3.10/15 erlaubt
        unsigned char* p = reinterpret_cast<unsigned char*>(&color32_);
        return p[idx];
      }
    
    private:
      uint32_t color32_;
    

    u.s.w.



  • hustbaer schrieb:

    Man hätte hier auch einfach ne Union nehmen können.

    Das ist nicht erlaubt, weil immer nur auf den letzten geschriebenen Wert lesend zugegriffen werden darf.



  • Michael E. schrieb:

    hustbaer schrieb:

    Man hätte hier auch einfach ne Union nehmen können.

    Das ist nicht erlaubt, weil immer nur auf den letzten geschriebenen Wert lesend zugegriffen werden darf.

    Der berühmte Union Trick...



  • union
    {
     uint32_t color32;
     uint8_t color8[4];
    }
    

    Weshalb ist das hier denn nun genau so "verboten"?
    Warum darf nur auf den zuletzt geschriebenen Wert zugegriffen werden?
    Weil du es sagst? Oder wurde das in der EULA der source sdk festgelegt. Oder hat das etwa religiöse Hintergründe? O_o
    Oder gibt es da einen c++ basierenden Grund? Eventuell weil man nicht sicher sagen kann ob der Compiler die 8-bit Typen auf 32bit (oder 64) aligned?

    Es schaut mir jedenfalls alles besser aus als das Original im ersten Post.



  • Osbios schrieb:

    Oder gibt es da einen c++ basierenden Grund?

    Ja. Der C++ Standard garantiert nicht, dass das so funktioniert, wie Du Dir das denkst.



  • krümelkacker schrieb:

    Osbios schrieb:

    Oder gibt es da einen c++ basierenden Grund?

    Ja. Der C++ Standard garantiert nicht, dass das so funktioniert, wie Du Dir das denkst.

    Ok, wieder etwas dazu gelernt.



  • krümelkacker schrieb:

    Osbios schrieb:

    Oder gibt es da einen c++ basierenden Grund?

    Ja. Der C++ Standard garantiert nicht, dass das so funktioniert, wie Du Dir das denkst.

    Der ein oder andere Compiler kann natürlich diese Garantie geben. So ist es zB beim GCC. Der GCC erlaubt den union-hack explizit. Er ist aber wie gesagt nicht Standard.



  • Michael E. schrieb:

    hustbaer schrieb:

    Man hätte hier auch einfach ne Union nehmen können.

    Das ist nicht erlaubt, weil immer nur auf den letzten geschriebenen Wert lesend zugegriffen werden darf.

    Ja, ist nicht erlaubt. Funktioniert aber genau so gut oder schlecht wie einfach "this" zu casten, und ist IMO zumindest weniger verwirrend.


Anmelden zum Antworten