使用联合类型成员时输出奇怪 §6.5.2.3 §6.2.6.2

问题描述

我的代码:

#include<stdio.h>

union U{
    int x;
    char y;
};

int main()
{
    union U u1;
    u1.x = 258;
    u1.y = '0';
    printf("%d%d",u1.x,u1.y);
    return 0;
}

奇怪的是,输出为30448

有人可以解释一下这是怎么回事吗?

解决方法

您可能会误解union的目的。它一次只能存储一个变量,但是此变量可以有多种类型。存储的最后一个变量将覆盖前一个变量。

在您的情况下,u1.y(即'0',请注意,'0'的1字节ASCII十进制表示形式为48)是最后存储的值,这对应于您通过其ASCII十进制表示形式打印'0'时输出的最后两位数字。

对于输出的第一部分,请注意,您使用以下命令覆盖了int变量258,该变量大概是4个字节(但为了解释起见,我假设它是2个字节)。 1个字节宽的char变量48

258的二进制值(假设2个字节宽的int)是:

|0|0|0|0|0|0|0|1|0|0|0|0|0|0|1|0|

|   2nd byte    |   1st byte    |              

48(1字节宽的char变量)的二进制值为:

| | | | | | | | |0|0|1|1|0|0|0|0|

                |   1st byte    | 

当用一个字节变量覆盖两个字节的并集变量时,只有8个最低有效位(最低有效字节)将被覆盖,因此您将得到:

|0|0|0|0|0|0|0|1|x|x|x|x|x|x|x|x|
| | | | | | | | |0|0|1|1|0|0|0|0|

|0|0|0|0|0|0|0|1|0|0|1|1|0|0|0|0|

这是304的二进制表示形式。

因此,您的代码首先打印2字节宽(为了示例)int 304,然后打印1字节宽int 48(ASCII { {1}}代表int),因此输出'0'

请注意,此行为是 不是 未定义的。

ISO/IEC 9899:2017 N2176

§6.5.2.3

97) 如果用于读取联合对象内容的成员与上次用于存储值的成员不同在对象中,值的对象表示形式的适当部分将重新解释为新类型的对象表示形式,如6.2.6(过程有时称为“类型调整”)所述。这可能是陷阱的表示形式。

§6.2.6.2

6 -将值存储在结构或联合类型的对象中(包括成员对象中)时,与任何填充字节对应的对象表示形式的字节采用未指定的值。 51)即使结构或联合对象的成员的值可能是陷阱表示,结构或联合对象的值也永远不会是陷阱表示。

7 - 当值存储在联合类型的对象的成员中时,该对象表示形式的字节与该成员不对应但与之对应其他成员采用未指定的值。

要确认,您可以使用:

30448

这将打印printf("%p %p\n",(void*)&u1.x,(void*)&u1.y); u1.x的内存地址,您将不会惊讶地发现它们相同。

,

除了最后一个

中,您不能一个工会的成员
#include<stdio.h>
union U{
int x;
char y;
};

int main()
{
    union U u1;
    u1.x = 258; // write into member x: OK
    u1.y = '0'; // write into member y: OK
    printf("%d%d",u1.x,u1.y); // read both member x and y: WRONG
                              // can only read member y
    return 0;
}

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...