C ++联合数据结构,可以轻松访问DWORD中的位

时间:2010-04-25 18:48:15

标签: c++ data-structures directx unions

我正在线上运行一组DirectX教程,我有以下结构:

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

我对directX的基本了解使我得到了颜色由8位alpha,红色,绿色和蓝色通道组成的东西。

我正试图让东方访问这些频道。而不是多次编写以下代码(在CUSTOMVERTEX结构中):

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

我可以用联合和结构的组合来写一个更优雅的结果,例如

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;
        };
    };
}

然而,这似乎没有按预期发挥作用,r,g和&中的值。 b几乎与颜色的反面有关,例如如果颜色是0x12345678 a = 0x78,则r = 0x56。这是一个忍耐问题吗?

此解决方案还可以期待其他问题吗?例如颜色成员溢出?

我想我要问的是......有更好的方法吗?!

3 个答案:

答案 0 :(得分:2)

是的,这是一个字节序问题。如果您只支持一个平台,则可以根据体系结构的字节顺序布置结构成员。如果您正在处理多个体系结构,则需要#define多个结构成员布局,这取决于字节顺序。

结构和工会对我来说总是看起来更优雅,但按位操作在两者中更容易携带。当我做这样的事情时,我将一个断言粘贴到我的启动代码中,以确保结构符合我期望它的大小,然后产生不确定的恶意。

在C ++中,您可以编写一个封装数据并为您执行操作的类。

答案 1 :(得分:1)

如果你的DWORD颜色是0x12345678,那么在little-endian系统中地址和颜色的字节是0x78。

联盟的技巧在技术上会导致未定义的行为。存取方法有什么问题?

答案 2 :(得分:1)

要使联合为此工作,您需要确保正确的结束问题,并且您需要确保填充问题是正确的(这将需要非标准的#pragma语句等)。即使您对可移植性不感兴趣(DirectX仅限Windows),我仍然建议您使用内联函数来实现此目的。你可能需要有几个非常相似的,但我可能会说这几个函数增加的复杂性仍然低于union。如果你改变编译器,他们可能更容易做对,破坏的机会更少(特别是打破静默),并且对于下一个阅读代码的人来说更容易确信他们正在做他期望的事情。

暂且不说 - 为什么使用#pragma pack(2)代替#pragma pack(1)

如果您使用#pragma pack,请不要忘记'保存&恢复'原始包装设置,以便其他东西不会出现意外行为:

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