首页 > 解决方案 > 使用联合类型成员时的奇怪输出

问题描述

我的代码:

#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

有人可以解释这是怎么发生的吗?

标签: ctypesunions

解决方案


您可能误解了union. 它意味着一次只存储一个变量,但这个变量可以有多种类型。最后存储的变量将覆盖前一个。

在您的情况下u1.y(即'0',提醒您 is 的 1 字节 ASCII 十进制表示'0'是相关的48)是存储的最后一个值,这对应于您'0'通过其 ASCII 十进制表示打印时输出的最后 2 位数字。

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

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(的 ASCIIint表示'0'),因此输出30448.

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

ISO/IEC 9899:2017 N2176

§ 6.5.2.3

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

§ 6.2.6.2

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

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

为了确认,您可以使用:

printf("%p %p\n", (void*)&u1.x, (void*)&u1.y);

这将打印两者的内存地址,u1.x并且u1.y您不会惊讶地发现它们是相同的。


推荐阅读