union umgedrehte Elemente?



  • Hallo,

    union A
    {
    	struct
    	{
    		unsigned char b;
    		unsigned char g;
    		unsigned char r;
    		unsigned char a;
    	};
    	unsigned long color;
    };
    
    int main()
    {
    	A a;
    	a.color = 0xff00ff00;
    	std::cout << (int)a.a << ' ' << (int)a.r << ' ' << (int)a.g << ' ' << (int)a.b;
    }
    

    Jener Code funzt! 🙂

    Aber wieso muss ich die unsigned chars in der union umdrehen, damit am Ende auch 0 255 0 255 rauskommt, in der richtigen Reihenfolge (rgba) sind sie nachher falschrum!

    MfG MAV



  • weil die CPU die Bytes in einer bestimmten Reihenfolge im Speicher ablegt.

    Leider gibts da zwei Varianten Little und Big Endian, welche Intel benutzt weis ich leider nicht

    Die Cpu´s von Motorola machens genau anders wie die Intel Cpu´s, leidvolle Erfahrung binärer Datentransfer über serielle Schnittstelle und
    die Daten waren verwurschtelt.

    Deswegen ist diese Art von Code auch nicht portabel.
    Solange du bei einer CPU-Familie bleibst ist das jedoch egal.



  • Der Code ist ohnehin nicht portabel, schon allein auf 64 Bit Plattformen ist long ja keine 4 Byte, sondern 8 Byte groß!

    ChrisM



  • ich glaube da gabs jetzt eine defacto Standardisierung

    short int 16 Bit
    long int 32 Bit
    long long int 64 Bit

    Bin mir aber nicht sicher

    der Begriff int bleibt undefiniert

    Falls es falsch sein sollte bitte korrigieren



  • Soweit ich weiß, wird zumindest beim MS-Compiler auf IA64 der int 4 Byte breit bleiben und long dafür 8 Byte breit werden - aus irgendwelchen Kompatiblitätsgründen. Aber es gibt ja noch boost/cstdint.hpp...



  • Und wie krieg ich dann ne 32 Bit Variable hin?

    DWORD?

    Aber das ist ja auch nur nach long definiert!



  • Wenn 'operator void' recht hat ist das einfach int

    Soweit ich weis ist und bleibt der Typ int Maschinenabhängig



  • int32_t. und dann gibts ja noch die bitweisen operatoren:

    unsigned green(unsigned color) { return (color >> 8) & 0xFF; }
    


  • union A 
    { 
        struct 
        { 
            unsigned char b; 
            unsigned char g; 
            unsigned char r; 
            unsigned char a; 
        }; 
        int32_t color; 
    };
    

    Ist das jetzt portierbar?
    Meine Programme sollen ja überall laufen, ansonsten las ich das mit der union einfach weg, aber das wäre ja eigentlich schoin praktisch so. 🙄

    MfG MAV



  • portierbar ist alles, portabel ist das nicht. hoerst du nicht zu? nicht alle prozessoren haben die gleiche endianness.



  • Folglich sind Unions allgemein nicht portabel?



  • Mis2com schrieb:

    Folglich sind Unions allgemein nicht portabel?

    Wenn du darauf abzielst, über "Unterstrukturen" Teile einer großen Struktur (wie hier) zu manipulieren, nein. Wenn man unions nutzt um z.B. einen float und einen int irgendwo platzsparend zu speichern und man nie beides braucht, ja. Du könntest natürlich Dinge machen wie

    #ifdef BIG_ENDIAN
    // Struktur in Big-Endian
    #else
    // Struktur in Little-Endian
    #endif
    

    Dann ist mit einem define das plattformabhängig gesetzt werden muss portierbar 😉



  • das geht besser als das define selbst zu machen, und interessanterweise ist eine union die loesung:

    const union{
        unsigned short dummy;
        struct { unsigned char LITTLE, BIG; } IS;
    } ENDIAN = { 1 };
    

    und dann if(ENDIAN.IS.BIG) und so. ist jetzt ausm gedaechtnis, aber prinzipiell wars so.



  • <bösezunge> Immer schön davon ablenken, dass sein Problem niemals mit unions gelöst werden sollte, sehr schön ^^. Oh ich vergaß, bitweise Operatoren sind nur für Freaks da, deshalb verwenden wir jetzt alle unions und #ifdefs. </bösezunge>

    Sorry, ich konnte nich anders.



  • @ Mr N.

    😃 Nicht einem den Mund wässrig machen und dann schweigen, wenn du eine bessere Lösung für sein
    Problem hast, raus damit! 😕



  • @pad:

    Mr. N schrieb:

    und dann gibts ja noch die bitweisen operatoren:

    unsigned green(unsigned color) { return (color >> 8) & 0xFF; }
    

    so.



  • Klar, bitweise Operatoren sind hier die andere Lösung, ich dachte nur, es ginge mit unions noch einfacher, aber den gedanken verwerf ichd ann lieber wieder. 🙂
    Gut, danke für eure Hilfe.

    Ciao



  • Noch etwas Überzeugungsarbeit:

    Auch perfomance-mäßig spricht einiges für die Bitoperationen. Disassembliert ergeben die beiden Varianten (union und Bits):

    // Variante 1:
    // int green1 = a.g;
    :0040101D 8B4DF5                  mov ecx, dword ptr [ebp-0B]
    :00401020 81E1FF000000            and ecx, 000000FF
    :00401026 894DF4                  mov dword ptr [ebp-0C], ecx
    // Variante 2:
    // int green2 = (Color >> 8) & 0xFF;
    :00401033 33D2                    xor edx, edx
    :00401035 8A55FD                  mov dl, byte ptr [ebp-03]
    :00401038 8955F8                  mov dword ptr [ebp-08], edx
    

    Beides Mal wird von einer ungeraden Adresse gelesen. Bei Variante 1 werden aber 32 Bit gefordert, d.h. der Prozessor muss effektiv 64 Bit lesen (über die ungerade Adresse hinaus). Ich bin mir nicht ganz sicher, ob das bei Variante 2 auch so ist, oder ob die CPU merkt, dass nur das unterste Byte gefordert ist. Auf jeden Fall ein Pro für Variante 2.
    Noch eins:
    Der Opcode für das "and" in Variante 1 ist viel länger als der des "xor" in Variante 2. 🙂


Anmelden zum Antworten