Meh*_*ari 58
A union
总是占用最大成员的空间.目前使用的无关紧要.
union {
short x;
int y;
long long z;
}
Run Code Online (Sandbox Code Playgroud)
上述实例union
总是至少long long
需要存储空间.
边注:正如指出的斯蒂法诺,实际空间的任何类型(union
,struct
,class
)将采取不依赖于其他问题,如编译器对齐.我没有简单地通过这个,因为我只想告诉工会考虑最大的项目.重要的是要知道实际尺寸确实取决于对齐.
Joh*_*itb 30
标准回答了C++标准第9.5节或C99标准第6.5.2.3节(或C11标准第6段)中的所有问题:
在联合中,最多一个数据成员可以在任何时间处于活动状态,也就是说,最多一个数据成员的值可以随时存储在并集中.[注意:为了简化联合的使用,我们做了一个特别的保证:如果一个POD-union包含几个共享一个公共初始序列的POD结构(9.2),并且这个POD-union类型的一个对象包含一个在POD结构中,允许检查任何POD结构成员的共同初始序列; 见9.2.] union的大小足以包含其最大的数据成员.每个数据成员都被分配,就好像它是结构的唯一成员一样.
这意味着每个成员共享相同的内存区域.这里是活跃在最一个成员,但你不能找出哪一个.您必须在其他地方存储有关当前活动成员的信息.除了union之外还存储这样的标志(例如,有一个结构,其中一个整数作为type-flag,union作为数据存储)将给你一个所谓的"区别联合":一个知道什么类型的联合它目前是"活跃的".
一个常见的用法是在词法分析器中,你可以使用不同的标记,但是根据标记,你有不同的信息存储(放入line
每个结构以显示常见的初始序列):
struct tokeni {
int token; /* type tag */
union {
struct { int line; } noVal;
struct { int line; int val; } intVal;
struct { int line; struct string val; } stringVal;
} data;
};
Run Code Online (Sandbox Code Playgroud)
标准允许您访问line
每个成员,因为这是每个成员的共同初始序列.
存在编译器扩展,允许访问所有成员而忽略当前存储其值的那个成员.这允许在每个成员之间有效地重新解释具有不同类型的存储比特.例如,以下内容可用于将float变量解析为2个unsigned short:
union float_cast { unsigned short s[2]; float f; };
Run Code Online (Sandbox Code Playgroud)
在编写低级代码时,这非常方便.如果编译器不支持该扩展,但无论如何都要支持,那么编写未定义结果的代码.因此,如果您使用该技巧,请确保您的编译器支持它.
Ste*_*ini 17
这取决于编译器和选项.
int main() {
union {
char all[13];
int foo;
} record;
printf("%d\n",sizeof(record.all));
printf("%d\n",sizeof(record.foo));
printf("%d\n",sizeof(record));
}
Run Code Online (Sandbox Code Playgroud)
这输出:
13 4 16
如果我没记错的话,它取决于编译器放入分配空间的对齐方式.因此,除非您使用某些特殊选项,否则编译器会将填充放入您的联合空间.
编辑:使用gcc你需要使用pragma指令
int main() {
#pragma pack(push, 1)
union {
char all[13];
int foo;
} record;
#pragma pack(pop)
printf("%d\n",sizeof(record.all));
printf("%d\n",sizeof(record.foo));
printf("%d\n",sizeof(record));
}
Run Code Online (Sandbox Code Playgroud)
这个输出
13 4 13
您也可以从反汇编中看到它(为了清楚起见,删除了一些printf)
0x00001fd2 <main+0>: push %ebp | 0x00001fd2 <main+0>: push %ebp
0x00001fd3 <main+1>: mov %esp,%ebp | 0x00001fd3 <main+1>: mov %esp,%ebp
0x00001fd5 <main+3>: push %ebx | 0x00001fd5 <main+3>: push %ebx
0x00001fd6 <main+4>: sub $0x24,%esp | 0x00001fd6 <main+4>: sub $0x24,%esp
0x00001fd9 <main+7>: call 0x1fde <main+12> | 0x00001fd9 <main+7>: call 0x1fde <main+12>
0x00001fde <main+12>: pop %ebx | 0x00001fde <main+12>: pop %ebx
0x00001fdf <main+13>: movl $0xd,0x4(%esp) | 0x00001fdf <main+13>: movl $0x10,0x4(%esp)
0x00001fe7 <main+21>: lea 0x1d(%ebx),%eax | 0x00001fe7 <main+21>: lea 0x1d(%ebx),%eax
0x00001fed <main+27>: mov %eax,(%esp) | 0x00001fed <main+27>: mov %eax,(%esp)
0x00001ff0 <main+30>: call 0x3005 <printf> | 0x00001ff0 <main+30>: call 0x3005 <printf>
0x00001ff5 <main+35>: add $0x24,%esp | 0x00001ff5 <main+35>: add $0x24,%esp
0x00001ff8 <main+38>: pop %ebx | 0x00001ff8 <main+38>: pop %ebx
0x00001ff9 <main+39>: leave | 0x00001ff9 <main+39>: leave
0x00001ffa <main+40>: ret | 0x00001ffa <main+40>: ret
Run Code Online (Sandbox Code Playgroud)
唯一的区别在于main + 13,编译器在堆栈0xd而不是0x10上分配
mou*_*iel 11
联合没有活动数据类型的概念.您可以自由地阅读和撰写工会的任何"成员":这取决于您解释所获得的内容.
因此,union的size始终是其最大数据类型的size.