C/C++中的联合体大小是多少?它是其中最 Big Data 类型的大小吗?如果是这样,编译器如何计算在联合的较小数据类型之一处于活动状态时如何移动堆栈指针?

推荐答案

本标准回答C++标准第9.5节,或C99标准第6.5.2.3节第5段(或C11标准第6段,或C18标准第6.7.2.1节第16段)中的所有问题:

在联合中,任何时候最多只能有一个数据成员处于活动状态,也就是说,任何时候最多有一个数据成员的值可以存储在联合中.[注意:为了简化联合的使用,有一个特殊的保证:如果POD联合包含几个共享公共初始序列(9.2)的POD struct ,并且如果此POD联合类型的对象包含其中一个POD struct ,则允许判断任何POD struct 成员的公共初始序列;参见9.2.]联合的大小足以包含其最大的数据成员.每个数据成员的分配就像它是 struct 的唯一成员一样.

这意味着每个成员共享相同的内存区域.最多有is个成员处于活动状态,但您无法找到哪一个.您必须将有关当前活动成员的信息存储到其他地方.除了联合存储这样一个标志(例如,有一个 struct ,其中一个整数作为类型标志,一个联合作为数据存储)将为您提供一个所谓的"有区别的联合":一个知道它当前是什么类型的联合.

一种常见的用法是在词法分析器中,您可以有不同的标记,但是根据标记的不同,要存储的信息也不同(将line放入每个 struct 中以显示公共初始序列是什么):

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;
};

标准允许您访问每个成员的line个,因为这是每个成员的公共初始序列.

存在允许访问所有成员的编译器扩展,而不管哪个成员当前存储了它的值.这允许高效地重新解释每个成员之间具有不同类型的存储比特.例如,以下内容可用于将一个浮点变量分解为2个无符号短码:

union float_cast { unsigned short s[2]; float f; };

这在编写低级代码时非常方便.如果编译器不支持该扩展,但您仍然支持它,那么您将编写结果未定义的代码.所以,如果你使用这个技巧,一定要确保你的编译器支持它.

C++相关问答推荐

Linux/C:复制修剪了最后一个填零孔的文件

C中的整字母后缀i是什么

海湾合作委员会是否保证大小匹配的访问?

变量的const视图是否定义良好?

在struct中调用函数,但struct在void中 *

特定闪存扇区的内存别名

C是否用0填充多维数组的其余部分?

为什么STM32G474RE上没有启用RCC PLL

在CLANG中调试预处理器宏

在Apple Silicon上编译x86的Fortran/C程序

Square不与Raylib一起移动

强制转换变量以在 struct 中蚕食

如何使用FSeek和文件流指针在C中查找文件的前一个元素和前一个减go 一个元素

有没有一种方法可以用C创建保留限定符的函数?

如何摆脱-WIMPLICIT-Function-声明

CS50 pset 5的皱眉脸正确地处理了大多数基本单词,并且拼写判断不区分大小写.

有没有办法减少C语言中线程的堆大小?

关于不同C编译器中的__attribute__支持

使用 GCC 将一个函数中初始化的 struct 体实例通过指针传递到 C 中的另一个函数会产生不同的结果

OpenGL 中的非渐变 colored颜色 变化