0

I have no idea how to decipher this man someone needs to tell me what is going on please help

typedef struct _ARGBCOLOR {
    union {
        struct {
            BYTE B;
            BYTE G;
            BYTE R;
            BYTE A;
        };
        DWORD ARGB;
    };
} ARGBCOLOR, *PARGBCOLOR;
timrau
  • 22,578
  • 4
  • 51
  • 64
y2k
  • 65,388
  • 27
  • 61
  • 86

5 Answers5

7

If you have a ARGBCOLOR x;You can access 4 separate bytes as x.B,x.G,x.R, and x.A, or a 32-bit word as x.ARGB.

The C standard guarantees these will overlay properly (assuming the sizes fit and padding requirements don't screw the pooch (not the case here)). But this struct clearly assumes a little-endian system.

One extra complication is that the union is anonymous. It's common to name a union like this u, but some compilers allow internal unions and structs to be anonymous, so its members are accessed as if they were up one level (at the same level as the union itself).

My favorite way to do this sort of overlay type is to put the union at the outermost level. You can duplicate the kind or type member so it's accessible everywhere. But this way removes the temptation to use anonymous unions (which are not available in Ansi-C or C99) because you don't need a bogus u member in the middle.

typedef union _ARGBCOLOR {
    //BYTE type;
    struct {
        //BYTE type;
        BYTE B;
        BYTE G;
        BYTE R;
        BYTE A;
    } bytes;
    struct {
        //BYTE type;
        DWORD ARGB;
    } word;
} ARGBCOLOR, *PARGBCOLOR;

Due to the common initial prefix property, all three of the BYTE type; members would overlay the same memory.

Another variation is to make an array for the individual bytes.

typedef union _ARGBCOLOR {
    DWORD dword;
    BYTE byte[ sizeof(DWORD)/sizeof(BYTE) ];
} ARGBCOLOR, *PARGBCOLOR;
enum { B,G,R,A };

Now we don't need two levels, and the type-punning is more apparent.

ARGBCOLOR x = { 0x10203040 };
x.byte[B] = 50;
x.byte[G] = 60;
printf("0x%8x\n", x.dword);  // prints: 0x10206050
luser droog
  • 18,988
  • 3
  • 53
  • 105
  • So the DWORD and the 4bytes point to the same data OR IS IT A COPY – y2k Jun 17 '13 at 07:00
  • 1
    It's the same data. A struct puts each member at a different offset based on the size of the members before it, but a union is just like a struct with all members at offset 0. – luser droog Jun 17 '13 at 07:02
  • 1
    Nitpick: This answer doesn't address the fact that you could just write `typedef union _ARGBCOLOR` and completely eliminate the outer struct. – Will Jun 17 '13 at 07:08
  • @Will Good point. I was debating whether to weigh in on that. – luser droog Jun 17 '13 at 07:09
  • 2
    Nitpick 2: anonymous members *are* in fact standardized -- in the C11 standard. Good comprehensive answer all together though. :) – Will Jun 17 '13 at 07:17
2

It does the same thing that declaring the structure outside of the union would do, but allows you to do it anonymously, exposing the struct's members as the same scope as the other union members. Your construct in particular allows you to do something like

ARGBCOLOR a;
printf("a = %u.%u.%u.%u or %lu\n", a.B, a.G, a.R, a.A, a.ARGB);

(The union itself lets you see it as one of the types within the union, in this case you can see it either as a sequence of four BYTE values or as a single DWORD value)

If you hoisted the struct definition out of the union:

struct ARGB_VALUES {
    BYTE B, G, R, A;
};
struct ARGBCOLOR {
    union {
        ARGB_VALUES VALUES; /* My god, how can you tell a type from a member? */
        DWORD ARGB;
    };
};

The previous printf would have to be:

ARGBCOLOR a;
printf("a = %u.%u.%u.%u or %lu\n", a.VALUES.B, a.VALUES.G, a.VALUES.R, a.VALUES.A, a.ARGB);

Note: The struct definition construct you're using is very archaic. You can reduce it as follows and save giving every structure/class a second alias that bloats your symbol table:

typedef struct ARGBCOLOR {
    ...
} *PARGBCOLOR;

The way you're doing it is equivalent to this:

struct _ARGBCOLOR {}; // First symbol.
typedef _ARGBCOLOR ARGBCOLOR;
typedef _ARGBCOLOR *PARGBCOLOR;
kfsone
  • 23,617
  • 2
  • 42
  • 74
1
typedef struct _ARGBCOLOR 
{
    union 
    {
        struct 
        {
            BYTE B;
            BYTE G;
            BYTE R;
            BYTE A;
        };

        DWORD ARGB;
    };
} ARGBCOLOR, *PARGBCOLOR;

If you observe carefully, you can see a struct and a DWORD within the union. You can use either of these from your typedefed struct ARGBCOLOR, whichever is available

Community
  • 1
  • 1
Suvarna Pattayil
  • 5,136
  • 5
  • 32
  • 59
1

The outermost struct is not really useful in your example, but it is when it has an additional member called kind or some such:

struct ARGBCOLOR {
    uint8_t kind;
    union {
        struct {
            BYTE B;
            BYTE G;
            BYTE R;
            BYTE A;
        };
        DWORD ARGB;
    };
} ARGBCOLOR;

Then depending on the value of kind you interpret the union as either a struct with members B, G, R and A, or the DWORD ARGB.

edit: Keep in mind that anonymous members such as the union and the inner struct only became part of the C standard in C11.

Will
  • 2,014
  • 2
  • 19
  • 42
1

In a union, each data member starts at the same location in memory. The DWORD ARGB shares the memory location of the struct with 4 bytes. So, the size of union will be 4 bytes and you may access it as either as a whole using ARGB or byte-wise, using A, R, G, or B (a single byte can be modified without affecting other bytes).

raj raj
  • 1,932
  • 1
  • 14
  • 15