cstructunionbit-fields

How do I fix this 5-bit boundary based union in C?


I have a system which expects a little endian 16-bit color value with three colors of 5 bit each and one alpha bit.

In big endian it looks like this:

R:{00000-11111} G:{00000-11111} B:{00000-11111} A:{0-1}

I tried to model that with

typedef union {
    
    struct {
        SceUChar8 R;
        SceUChar8 G;
        SceUChar8 B;
        SceUChar8 A;
    }  components;
    
    SceUInt32 Value;
} mgpColor8888;
    
    
typedef union {
    
    struct {
        SceUChar8 R: 5;
        SceUChar8 G: 5;
        SceUChar8 B: 5;
        SceUChar8 A: 1;
    }  components;
    
    SceUShort16 Value;
} mgpColor5555;

But the mgp5555 is somehow bugged as a I need the union to create a 16-bit type.

typedef union {

    struct {
    
    >>5 bits<< R: 5;
    >>5 bits<< G: 5;
    >>5 bits <<B: 5;
    >>1 bits << A: 1;
    }  components;
    
    SceUShort16 Value;
    } mgpColor5555; 

I've hit a brick wall.

The code blow works since I set up the 16-bit value manually instead of using unions like I want to:

SceUShort16 gen5551( SceUChar8  R, SceUChar8  G, SceUChar8  B, SceUChar8  A) {
    
     mgpColor5555 val;
     R >>=3;
     G >>=3;
     B >>=3;
     A= (A >= 0x80) ? 0b01 : 0b00;
     SceUShort16 temp = ((A & 1) << 15) |((B & 0x1F) <<10 )  | ((G & 0x1F) << 5)| (R & 0x1F);
     val.Value = temp;
     return val.Value;
}

Why isn't union mgpColor5555 above working?


Solution

  • How do I fix this 5-bit boundary based union in C?

    Bit fields are not portable. Use bit operations. Write your own wrappers, setters and getters, for accessing the 5-bit fields you want to get.

    I would do something along:

    struct { uint8_t R, G, B, A; } mgpColor8888;
    struct { uint8_t R :5, G :5, B :5, A :1; } mgpColor5555;
    #define mgpColor5555_INIT(R, G, B, A)  (struct mgpColor5555){ \
       R>>3, G>>3, B>>3, A>=0x80 }
    uint16_t mgpColor5555_to_16(const struct mgpColor5555 *t) {
       return ((t->A & 1) << 15) |((t->B & 0x1F) <<10 )  | ((t->G & 0x1F) << 5)| (t->R & 0x1F);
    }