开发者

C++ union data-structure, easy access of bits within a DWORD

I'm running through a set of DirectX tutorials online and I have the following structure:

struct CUSTOMVERTEX
{
FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag
DWORD color;        // from the D3DFVF_DIFFUSE flag
}

My basic understanding of directX leads me to thing tha color is made up of 8-bit alpha, red, green and blue channels.

I am attempting to get east access to these channels. Rather than write the following code numerous times (within the CUSTOMVERTEX structure):

public: int red()
{
    return (color & 0x00FF0000) >> 16;
}

I could write a more elegant somution with a combination of a union and a structure e.g.

struct CUSTOMVERTEX
{
    FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag

    #pragma pack(2)
    union 
    {
        DWORD color;        // from the D3DFVF_DIFFUSE flag

        struct
        {
            char a;
            char r;
            char g;
            char b;
        };
    };
}

However this does not appear to function as expected, the values in r, g, & b almost appear the reverse of whats in color e.g. if color is 0x12345678 a = 0x78, r = 0x56. Is this an endieness issue?

Also what other prob开发者_如何学Clems could I be expecting from this solution? e.g. overflow from the color members?

I guess what I'm asking is ... is there a better way to do this?!


Yes, this is an endianness issue. If you are supporting just one platform, you can lay out the struct members according to the architecture's endianness. If you are dealing with multiple architectures, you will need #define multiple struct member layouts, dependent on endianness.

Structs and unions always look more elegant to me, but bitwise operations are the more portable of the two. When I do stuff like this, I stick an assert into my startup code to make sure the struct is the size I expect it to me, before indeterminate nastiness ensues.

In C++, you might write a class that encapsulates your data and performs your operations for you.


If Your DWORD color is 0x12345678, the byte at the address &color is 0x78 in a little-endian system.

The trick with the union technically leads to an undefined behaviour. What's wrong with the accessor method?


To make a union work for this you need to make sure you have the endianess issues correct, and you need to make sure that padding issues are correct (which will require non-standard #pragma statements or such). Even if you're not interested in portability (DirectX being Windows only), I'd still suggest that you use the inline functions for this purpose. You may need to have several very similar ones, but I might argue that the added complexity of those several functions is still less than the union. They're probably easier to get right, will have less chance of breaking (especially breaking silently) if you change compilers, and will be easier for the next guy reading the code to be confident that they're doing what he expects.

As an aside - why did you use #pragma pack(2) instead of #pragma pack(1)?

And if you do use #pragma pack don't forget to 'save & restore' the original pack settings so other stuff doesn't behave unexpectedly:

#pragma pack(push)
#pragma pack(2)
//...
#pragma pack(pop)
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜