一个联合体本身是否是标准布局类型?

4
如果我有一个像这样的标准布局类型:
struct sl_t
{
  int a;
};

还有这样一个联合体:

union un_t
{
  int b;
  double q;
};

我能否将联合体作为结构类型进行转换和使用?也就是说,我能否假设联合体本身是一个标准布局类型,并且数据在内存的开头对齐?

un_t obj;
sl_t * s = reinterpret_cast<sl_t*>(&obj);
s->a = 15;
assert( obj.b == 15 );

我必须使用联合体中变量的地址 &obj.b 吗?

请注意,如果我将结构体存储在联合体内部,根据C++11标准的9.5-1规定,我可以访问sl_t::a和un_t::b。


2
但是... &obj.b 不是更短更安全吗?我很好奇你的动机。 - Dietrich Epp
我实际上仍然需要在它周围使用reinterpret_cast。我主要是出于好奇,但我确实有一个情况,可以方便地依赖它。 - edA-qa mort-ora-y
1个回答

3
似乎你的问题是对齐,看看 pragma pack 。结构体/联合名称只是引用分配的内存块,如果通过添加更多成员将 st_t.a 置于结构体中,则您的强制转换将失败,但如果它仍然是第一个成员,则会起作用,因为联合体的所有成员指向与联合本身相同的地址。
请参见C++标准的9.2.17-21节: “使用reinterpret_cast合理转换的指向标准布局struct对象的指针指向其初始成员(或者如果该成员是位域,则指向其中所在的单位),反之亦然。”
另请参见 9.5 节 Union: “1. 在联合中,最多只能同时激活一个非静态数据成员,也就是说,在联合中最多只能存储一个非静态数据成员的值。[注:为了简化使用联合而做出一个特殊保证:如果一个标准布局联合包含几个共享通用初始序列(9.2)的标准布局struct,并且如果这种标准布局联合类型的对象包含一个标准布局struct,则允许检查任何标准布局struct成员的公共初始序列;参见9.2。—结束说明]联合体的大小足以容纳其非静态数据成员中的最大值。每个非静态数据成员都被分配,好像它是一个struct的唯一成员。”

我对不使用任何编译器扩展的情况下,是否有效感兴趣。 - edA-qa mort-ora-y
@edA-qa mort-ora-y:我扩展了我的回答,是的,它是有效的,但仅限于我所解释的情况。 - slashmais
1
你的第二条评论,标准确实保证联合成员的地址与本身的地址相同吗?这是我没有找到的,但是如果是这样的话,那我的转换就是有效的。当然,如果 st_t.a 不再是第一个成员,那它也不会起作用。 - edA-qa mort-ora-y
你必须分配 sizeof(union) 的大小,尽管联合体的大小等于其最大成员的大小,但我仍然找不到任何参考资料表明其他成员共享一个地址。请注意,实际上(所有已知的编译器)都是像你所说的那样。 - edA-qa mort-ora-y
我也读了那些位,我在我的问题中提到了9.5-1。每个成员在内部都是标准布局,但这仍然不意味着联合的地址等于其成员的地址。也就是说,如果其成员都是标准布局,那么联合本身是否是标准布局类? - edA-qa mort-ora-y
好的,我会假设9.5与9-8结合起来确实表达了我的意思。第8条款似乎表明包含标准布局类的联合体是一个标准布局联合体。对我来说已经足够了。 - edA-qa mort-ora-y

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接