C语言中联合体的内存分配

4

最近我在学习union,但即使阅读了很多相关资料,仍然感到困惑。

#include<stdio.h> 
union test
{
    int x;
    char arr[4];
    int y;
};

int main()
{
    union test t;
    t.x = 0;
    t.arr[1] = 'G';
    printf("%s\n", t.arr);
    printf("%d\n",t.x);
    return 0;
}

我理解的是:
由于 x 和 arr[4] 共享同一块内存空间,当我们将 x 赋值为 0 时,arr 中的所有字符都被设置为 0。0 是 '\0' 的 ASCII 值。当我们使用 "t.arr[1] = 'G'" 后,arr 变为 "\0G\0\0"。当我们使用 "%s" 格式化字符串并打印时,printf 函数从第一个字符开始打印,并持续打印直到找到 '\0' 字符。由于第一个字符本身就是 '\0',所以什么也没打印出来。
我不明白的是第二个 printf 语句。
现在由于 arr[] 是 "\0G\0\0",相同的位置与 x 和 y 共享。 所以我认为 x 应该是以下内容
00000000 01000111 00000000 00000000 ("\0G\0\0")
因此 t.x 应该打印 4653056。 但它实际上打印了 18176。
我错在哪里?
这是技术上未定义的,还是由于某些愚蠢的错误或者是我缺失了某些概念??

1
你的机器是“大端序”。例如,尝试设置t.x = 0x0a0b0c0d; - joop
arr[3], arr[2], !!! arr[1] !!!, arr[0]. arr[3]arr[2],**!!!** arr[1] **!!!**,arr[0] - CristiFati
顺便说一下,char arr[4]; => char arr[sizeof(int)]; - Stargateur
嗯嗯。如果代码使用了printf("%x\n",(unsigned) t.x);,输出可能会更明显一些。 - chux - Reinstate Monica
2个回答

9
所有联合体成员将共享相同的公共内存。假设联合体的起始地址为0x100。当您编写t.x = 0;时,整个4字节都被初始化为零。
-------------------------------------------------
| 0000 0000 | 0000 0000 | 0000 0000 | 0000 0000  |
-------------------------------------------------
0x104     0x103       0x102        0x101        0x100
                                                 x,arr,y 

当你写下t.arr[1] = 'G';时,arr[1]会被覆盖为'G'的ASCII值,看起来像这样

-------------------------------------------------
| 0000 0000 | 0000 0000 | 0100 0111 | 0000 0000  |
-------------------------------------------------
0x104     0x103       0x102        0x101        0x100 

现在计算的值是18176。


好的,我知道我的机器是“大端序”的。 - SanQA

2

简化版:字节序问题!

当printf从您的联合指向的内存读取数据时,它会查看您系统的字节序,并以小端方式读取存储在其中的数据。 因此,它不会按照内存中的存储方式(0x00470000)打印数据,而是获取数字0x00004700,这对应于18176。

代码示例:

#include<stdio.h> 
union test
{
    int x;
    char arr[4];
    int y;
};

int main()
{
    union test t;
    t.x = 0;
    t.arr[1] = 'G';
    printf("%s\n", t.arr);
    printf("%d\n",t.x); // prints 18176

    t.x = 0;
    t.arr[2] = 'G';
    printf("%d\n",t.x); // prints 4653056
    return 0;
}

或者在Python中:

import struct

union_data = "\x00G\x00\x00"
print struct.unpack("<I", a)[0] # This is little endian. Prints 18176
print struct.nupack(">I", a)[0] # This is big endian. Prints 4653056

奖励! 您还可以使用函数 htonl 将以 little endian 读取的整数转换为 big endian。 在文档中查看更多信息


我不太同意。请查看@achal的答案。 - CristiFati

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接