【问题标题】:union vs bit masking and bit shifting联合与位掩码和位移
【发布时间】:2013-02-07 06:44:53
【问题描述】:

使用unions 存储一些信息(如一系列字节)并能够一次或一个一个地访问它们时有什么缺点。

示例:颜色可以用 RGBA 表示。所以颜色类型可以定义为,

typedef unsigned int RGBAColor;

然后我们可以使用位的“移位和屏蔽”来“检索或设置”RGBAColor 对象的红色、绿色、蓝色、alpha 值(就像在 Direct3D 函数中使用宏函数如 @987654324 @)。

但是如果我使用联合呢,

union RGBAColor
{
unsigned int Color;
struct RGBAColorComponents
{
    unsigned char Red;
    unsigned char Green;
    unsigned char Blue;
    unsigned char Alpha;
} Component;
};

然后我就不需要总是为读取或写入颜色分量进行移位 (<<) 或屏蔽 (&)。但这有问题吗? (我怀疑这有一些问题,因为我没有看到有人使用这种方法。)

字节顺序会成为问题吗?如果我们总是使用Component 访问颜色组件并使用Color 访问整个事物(用于复制、分配等),那么字节序应该不是问题,对吧?

-- 编辑-- 我发现一个旧帖子是同样的问题。所以我想这个问题有点转贴:P 抱歉。这是链接:Is it a good practice to use unions in C++?

根据答案,在给定示例中使用联合似乎在 C++ 中是可以的。因为那里没有数据类型的变化,它只是访问相同数据的两种方式。如果我错了,请纠正我。谢谢。 :)

【问题讨论】:

    标签: c++ c unions bit-shift bitmask


    【解决方案1】:

    联合的这种用法在 C++ 中是非法的,其中联合包含重叠但互斥的对象。你不能写一个工会的成员,然后读出另一个成员。

    在 C 语言中这是合法的,这是推荐的类型双关语。

    这与(严格)别名问题有关,这是编译器在尝试确定具有不同类型的两个对象是否不同时面临的难题。语言标准不同意,因为专家仍在研究可以在不牺牲性能的情况下安全地提供哪些保证。就个人而言,我避免所有这些。 int 实际上是用来做什么的?安全的翻译方法是复制字节,如memcpy。

    还有字节顺序问题,但这是否重要取决于您想用int 做什么。

    【讨论】:

    • 呃,没有。使用联合来重新解释数据与弃用完全相反,它被编入 C11 作为现有实践的标准化。 union { struct foo x; unsigned y[4]; }; 基本上是当您对memcpy() 过于擅长时,在类型之间混洗位的新的首选 方式。严格的别名规则是您在投射指针时打破的,例如,(unsigned *) &x。是的,我的意思是“新”——只有在过去十年中,编译器的“进步”才给那些违反实际严格别名规则的人带来了问题。
    • 因此,如果我理解正确,根据严格别名规则,问题是如果我在联合内部使用指针,如 union { unsigned int * pi; unsigned char * pc; }。并且很好用union { unsigned int val; unsigned char vals[4]; } 。 (我不知道这个严格的别名规则。所以请原谅我。我正在阅读this article。)
    • 就 C++ 而言,union 技术是这样做的事实上的方法,正是因为 (1) 它不会破坏严格的别名 (2) 其他技术确实会破坏严格的别名(3) 如果你打破严格的别名,你可能会遇到问题。也就是说,假设您不能使用 memcpy() 并且您没有投射到 unsigned char,这无论如何都可以。
    • @DietrichEpp This 和 this answer 表明 union 的别名在 C 中是可以的,而不是在 C++ 中。 C++ 允许memcpy,它在对象的生命周期开始之前有效地对其进行初始化。但它不允许两个对象同时居住在同一个地方。
    • @DietrichEpp 如果事实上的做法是UB,那么它仍然需要改变。规则就是它们被定义的任何东西;民意并不重要。
    【解决方案2】:

    我相信使用联合可以解决任何与字节序相关的问题,因为 RGBA 顺序很可能是按网络顺序定义的。此外,每个组件将是 uint8_t 或类似的事实,可以帮助一些编译器使用符号/零扩展加载,将低 8 位直接存储到非对齐字节指针,甚至能够并行化一些字节操作(例如 arm 有一些打包的4x8 位指令)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-29
      • 2013-01-27
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多