2

我正在在线浏览一组 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。这是一个endieness问题吗?

我还可以从这个解决方案中期待什么其他问题?例如从颜色成员溢出?

我想我要问的是......有没有更好的方法来做到这一点?!

4

3 回答 3

2

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

结构和联合对我来说总是看起来更优雅,但按位运算是两者中更便携的。当我做这样的事情时,我会在我的启动代码中添加一个断言,以确保结构是我期望的大小,然后再出现不确定的问题。

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

于 2010-04-25T19:03:16.087 回答
1

如果您的 DWORD 颜色为 0x12345678,则地址 &color 处的字节在 little-endian 系统中为 0x78。

从技术上讲,联合的技巧会导致未定义的行为。访问器方法有什么问题?

于 2010-04-25T18:59:23.200 回答
1

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

顺便说一句-您为什么使用#pragma pack(2)而不是#pragma pack(1)

如果您确实使用#pragma pack了,请不要忘记“保存并恢复”原始包设置,以免其他内容出现意外行为:

#pragma pack(push)
#pragma pack(2)
//...
#pragma pack(pop)
于 2010-04-25T19:58:27.800 回答