请考虑以下代码:
union U
{
int a;
float b;
};
int main()
{
U u;
int *p = &u.a;
*(float *)p = 1.0f; // <-- this line
}
我们都知道联合字段的地址通常是相同的,但我不确定是否有明确定义的行为来做这样的事情。
所以,问题是:在上面的代码中,如何投射和取消引用指向union字段的指针是否合法且定义明确?
P.S。我知道它比C ++更多C,但是我试图理解它在C ++中是否合法,而不是C。
答案 0 :(得分:6)
工会的所有成员必须居住在同一地址,这是由标准保证的。您所做的确实是明确定义的行为,但应注意您不能使用相同的方法从联合的非活动成员中读取。
注意:不要使用c风格的演员表,在这种情况下更喜欢
reinterpret_cast
。
只要您所做的只是写到union
的其他数据成员,行为就会明确定义;但正如所述,这种变化被认为是union
的活跃成员;这意味着你以后只能阅读你刚才写的内容。
union U {
int a;
float b;
};
int main () {
U u;
int *p = &u.a;
reinterpret_cast<float*> (p) = 1.0f; // ok, well-defined
}
注意:对于布局兼容的类型,上述规则有例外。
这个问题可以改写为以下代码片段,它在语义上等同于&#34;问题&#34;的简化版本。
#include <type_traits>
#include <algorithm>
#include <cassert>
int main () {
using union_storage_t = std::aligned_storage<
std::max ( sizeof(int), sizeof(float)),
std::max (alignof(int), alignof(float))
>::type;
union_storage_t u;
int * p1 = reinterpret_cast< int*> (&u);
float * p2 = reinterpret_cast<float*> (p1);
float * p3 = reinterpret_cast<float*> (&u);
assert (p2 == p3); // will never fire
}
n3797
)说什么?9.5/1 Unions [class.union]
在联合中,最多只有一个非静态数据成员可以 在任何时候都是活跃的,也就是说,最多只有一个 非静态数据可以随时存储在并集中。 [...]联合的大小足以包含最大的 其非静态数据成员。每个非静态数据成员都是 分配好像它是结构的唯一成员。 union对象的所有非静态数据成员都具有相同的地址。
注意:C ++ 11中的措辞(n3337)未被指定,即使意图一直是C ++ 14的意图。
答案 1 :(得分:3)
是的,这是合法的。使用显式强制转换,您几乎可以做任何事情。
正如其他评论所述,union
中的所有成员都在相同的地址/位置开始,因此向不同的成员投射指针是没有意义的。
汇编语言将是相同的。你想让代码易于阅读,所以我不推荐这种做法。令人困惑,没有任何好处。
另外,我推荐&#34;类型&#34;字段,以便您知道数据何时采用float
格式与int
格式。