Bar*_*rry 7 c++ gcc g++ unions
考虑以下类型:
struct A { int x; };
struct B { int y; char z; };
union U { A a; B b; };
Run Code Online (Sandbox Code Playgroud)
而这段代码片段:
U u;
new (&u.b) B;
b.y = 42;
b.z = 'x';
Run Code Online (Sandbox Code Playgroud)
在这一点上,读取u.a.x是明确定义的行为(并将产生42),因为它在共同的初始序列中.写至u.a.x是不确定的行为.
但是gcc允许通过联合进行类型惩罚 - 文档明确允许读取非活动成员,而不管成员顺序如何.gcc是否允许写入非活动成员,甚至是常见的初始序列,或者这仍然是gcc上未定义的行为?也就是说,如果在这一点上,我有:
void write(A& arg) { a.x = 17; }
write(&u.a); // generally undefined behavior, since active member is u.b
// but does gcc allow it?
f(u.b.y); // is this definitely f(17)?
g(u.b.z); // ... and is this definitely g('x')?
Run Code Online (Sandbox Code Playgroud)
您所描述的行为(称为 \xe2\x80\x9c类型双关\xe2\x80\x9d)是允许的,但 C++ 规范未定义(请参阅下面的注释)。它可能在特定的编译器和硬件下定义。\n更具体地说,在具有简单类型(char、short、float、double...)的 gcc 和 x86 上,这将充当不同字段之间的重新解释强制转换。
\n\n\n\n\n...从与最近写入的成员不同的联合成员(称为 \xe2\x80\x9ctype-punning\xe2\x80\x9d)读取的做法很常见。即使使用
\n-fstrict-aliasing,也允许类型双关,只要通过联合类型访问内存即可。(来源)
此外,有时它很有用,例如从设备(例如套接字)读取时:
\n\nunion {\n struct {\n int a;\n char b;\n short c;\n } data;\n\n char buf[128];\n} u;\n\nread_from_device(u.buf, 128);\nprintf("Data (a,b,c): (%d,%d,%d)\\n", u.data.a, u.data.b, u.data.c);\nRun Code Online (Sandbox Code Playgroud)\n\n首先,我们从设备读取原始数据,然后使用结构将其重新解释为数字。\n我们经常使用#pragma packon astruct来确保数据的打包方式与设备上的打包方式相同。
活动成员的确定是隐式的,并且仅由程序员而不是编译器确定。由您决定哪个成员处于活动状态。\n该字段的生命周期从您分配给该字段时开始。
\n\n\n\n\n...其生命周期的开始顺序是在左右操作数的值计算之后和赋值之前。
\n
事实上,手册指定写入非活动字段使其成为活动字段,这表明这是允许的。
\n\n请参阅此了解更多信息:
\n\n\n\n\n会员生命周期
\n\n联合成员的生命周期从成员激活时开始。\n 如果另一个成员之前处于活动状态,则其生命周期结束。
\n\n当联合体的活动成员由 E1 = E2 形式的赋值表达式切换时,该表达式使用内置赋值运算符或普通赋值运算符,对于成员访问中出现的每个联合成员 X和 E1 的数组下标子表达式\n 不是具有非平凡或已删除默认构造函数的类,如果\n 修改 X 在类型别名\n 规则下将具有未定义的行为,则隐式创建 X 类型的对象\n 指定存储;不执行初始化,并且其生命周期的开始顺序是在左操作数和右操作数的值计算之后、赋值之前。
\n
union A { int x; int y[4]; };\nstruct B { A a; };\nunion C { B b; int k; };\nint f() {\n C c; // does not start lifetime of any union member\n c.b.a.y[3] = 4; // OK: "c.b.a.y[3]", names union members c.b and c.b.a.y;\n // This creates objects to hold union members c.b and c.b.a.y\n return c.b.a.y[3]; // OK: c.b.a.y refers to newly created object\n}\n\nstruct X { const int a; int b; };\nunion Y { X x; int k; };\nvoid g() {\n Y y = { { 1, 2 } }; // OK, y.x is active union member (9.2)\n int n = y.x.a;\n y.k = 4; // OK: ends lifetime of y.x, y.k is active member of union\n y.x.b = n; // undefined behavior: y.x.b modified outside its lifetime,\n // "y.x.b" names y.x, but X\'s default constructor is deleted,\n // so union member y.x\'s lifetime does not implicitly start\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
408 次 |
| 最近记录: |