我之前很舒服地使用了工会;今天当我看到这篇文
union ARGB { uint32_t colour; struct componentsTag { uint8_t b; uint8_t g; uint8_t r; uint8_t a; } components; } pixel; pixel.colour = 0xff040201; // ARGB::colour is the active member from now on // somewhere down the line, without any edit to pixel if(pixel.components.a) // accessing the non-active member ARGB::components
实际上是未定义的行为,即从最近写入的联合成员之外的成员读取会导致未定义的行为。如果这不是联合的预期用途,那是什么?有人可以详细解释一下吗?
更新:
我想在事后澄清一些事情。
如果标准布局联合包含多个共享公共初始序列的标准布局结构,并且此标准布局联合类型的对象包含标准布局结构之一,则允许检查任何标准布局的公共初始序列标准布局结构成员。拥抱9.2/19:如果对应的成员具有布局兼容的类型,并且两个成员都不是位域或两者都是一个或多个初始序列的具有相同宽度的位域,则两个标准布局结构共享一个共同的初始序列成员。
这就是联合的目的——一个可以合法地持有几种类型中的任何一种的单一变量。[…] 只要用法一致:检索到的类型必须是最近存储的类型。程序员有责任跟踪当前存储在联合中的类型;如果将某些内容存储为一种类型并提取为另一种类型,则结果取决于实现。
联合的使用对于数据的兼容性可能是必不可少的 […] 有时误用于“类型转换 ”。
最重要的是,提出这个问题(自我问起,其标题保持不变)的目的是了解联合的目的,而不是标准允许的内容。 例如,当然,C++ 标准允许使用继承进行代码重用,但是这不是将继承作为 C++ 语言特性引入的目的或初衷。这就是安德烈的答案继续被接受的原因。
工会的目的很明显,但由于某种原因,人们经常错过它。
联合的目的是 通过使用相同的内存区域在不同的时间存储不同的对象 来节省内存。 就是这样。
这就像酒店的房间。不同的人在其中生活的时间不重叠。这些人从不见面,而且通常对彼此一无所知。通过适当管理房间的分时(即确保不同的人不会同时被分配到一个房间),一个相对较小的酒店可以为相对大量的人提供住宿,这就是酒店是给。
这正是工会所做的。如果您知道程序中的多个对象保存具有非重叠值生命周期的值,那么您可以将这些对象“合并”到一个联合中,从而节省内存。就像酒店房间在每个时刻最多有一个“活跃”租户一样,工会在计划时间的每个时刻最多有一个“活跃”成员。只能读取“活动”成员。通过写入其他成员,您将“活动”状态切换到该其他成员。
出于某种原因,工会的最初目的被完全不同的东西“覆盖”了:编写工会的一个成员,然后通过另一个成员检查它。这种内存重新解释(又名“类型双关语”) 不是对联合的有效使用。 它通常会导致未定义的行为,在 C89/90 中被描述为产生实现定义的行为。
编辑: 使用联合用于类型双关语(即写一个成员然后读取另一个成员)在 C99 标准的技术勘误之一中给出了更详细的定义(参见DR#257和DR#283)。但是,请记住,形式上这并不能保护您免于尝试读取陷阱表示而陷入未定义的行为。