C++联合数据结构,轻松访问 DWORD 中的位
我正在在线浏览一组 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问题吗?
另外,我还可以从这个解决方案中期待什么其他问题?例如从颜色成员溢出?
我想我要问的是......有更好的方法吗?
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 problems 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?!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
是的,这是一个字节顺序问题。如果您仅支持一个平台,则可以根据体系结构的字节顺序布置结构成员。如果您正在处理多个体系结构,则需要 #define 多个结构成员布局,具体取决于字节顺序。
对我来说,结构和联合总是看起来更优雅,但按位运算是两者中更便携的。当我做这样的事情时,我会在启动代码中添加一个断言,以确保该结构的大小符合我的预期,然后再发生不确定的麻烦。
在 C++ 中,您可以编写一个类来封装您的数据并为您执行操作。
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.
如果您的 DWORD 颜色为 0x12345678,则在小端系统中,地址 &color 处的字节为 0x78。
从技术上讲,工会的伎俩会导致未定义的行为。访问器方法有什么问题?
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?
要使联合为此工作,您需要确保字节序问题正确,并且需要确保填充问题正确(这将需要非标准
#pragma
语句等) 。即使您对可移植性不感兴趣(DirectX 仅适用于 Windows),我仍然建议您为此目的使用内联函数。您可能需要有几个非常相似的函数,但我可能会认为这几个函数增加的复杂性仍然低于union
。它们可能更容易正确,如果您更改编译器,则破坏(尤其是无声破坏)的机会会更少,并且下一个阅读代码的人会更容易确信他们正在做他所期望的事情。顺便说一句 - 为什么你使用
#pragma pack(2)
而不是#pragma pack(1)
?如果您确实使用
#pragma pack
,请不要忘记“保存并保存”。恢复'原始包设置,这样其他东西就不会出现意外行为: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 theunion
. 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: