关于联合和多个整数值

Regarding union and multiple integer values

我正在学习 C 并尝试使用 union。我的代码如下:

#include <stdio.h>

union date {
 int year  ;
 char month;
 char day  ;
 };

int main() {
 union date birth;
 birth.year = 1984;
 birth.month = 7;
 birth.day = 28;
 printf("%d, %d, %d\n",birth.year, birth.month, birth.day);
 // return 1820,28,28
 return 0;
}

我知道因为联合,birth.year 的值为 0111 0001 1100,即 1820。但我不明白为什么 birth.month return 的值为 28。

我认为您误解了工会的目的。如果你想要一个存储一组属性的对象(例如 d.yeard.monthd.day),你需要一个结构。

简而言之,联合让您可以将多种不同类型中的一种放入单个变量中。比如说你正在实现一个文件系统。假设您想要一个变量 current_block,它可以引用超级块或数据块,分别由 struct super_blockstruct data_block 定义。那么你可以这样做:

union block_generic{
    struct super_block;
    struct data_block;
}

union block_generic current_block;

现在 current_block 可以是 super_block 或 data_block。

编辑:只是想添加一个关于联合的实际用法的快速附录。继续上面的示例,将 current_block 视为超级块,例如,为了访问文件系统的索引节点数,您可以执行 current_block.super_block.n_inodes (我想指出的是您不需要直接处理联合变量,你指定哪个 "type hat," 可以这么说,它应该穿。

联合是 C 中可用的一种特殊数据类型,它允许将不同的数据类型存储在同一内存位置。

也就是说,您必须一次使用一个变量。

http://www.tutorialspoint.com/cprogramming/c_unions.htm

引用 C11,章节 §6.7.2.1,(强调我的

The size of a union is sufficient to contain the largest of its members. The value of at most one of the members can be stored in a union object at any time. A pointer to a union object, suitably converted, points to each of its members (or if a member is a bitfield, then to the unit in which it resides), and vice versa.

所以,你的预期基础是错误的。您不能同时拥有所有个工会成员的值,您只能拥有一个。

另外,从第 6.5.2.3 章,脚注 95,

If the member used to read the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is re-interpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called ‘‘type punning’’). This might be a trap representation.

这里,最后赋值day恰好和month的大小相同,所以当你尝试读取day时,它returns month.

的值

这完全误解了工会是什么。联合是一组值,它们都从相同的内存位置开始;如果你想在一种数据类型中存储多个单独的值,你需要使用的是结构。

例如,对于工会,您可以这样做:

#include <stdio.h>
#include <stdint.h>

typedef union _myunion
{
    int32_t s;
    uint32_t u;
} myunion;

int main()
{
    myunion u;
    u.s = -1;
    printf("%d %u\n", u.s, u.u);
    return 0;
}   

输出:

-1 4294967295

基本上,您分配一个值,所有联合成员都获得该值;如果它在不同类型中有不同的表示,那就这样吧。

在一个结构中,每个变量都占据自己的内存位置,因此如果您想将包括年、月和日的完整日期作为单独的变量存储在结构中,您可以毫无问题地这样做。

联合将其所有成员存储在同一个 space 中,并且 space 中存在的数据对应于最后写入的任何一个成员。工会与其最大的成员一样大。您没有提及您的特定平台,但假设现代 x86 Windows、MacOS 或桌面 Linux、char 可能是 8 位和 int 上的相当新的 GCC可能是 32 位,使你的日期联合看起来像这样:

0000 0000 0000 0000 0000 0000 0000 0000
\_______________ year ________________/
\ month /
\_ day _/

让我们来看看您对 union date birth 的使用,好吗?从 birth.year = 1984; 开始,我们有(请记住 x86 是 little endian

1100 0000 0000 0111 0000 0000 0000 0000
\_______________ year ________________/
\ month /
\_ day _/

然后birth.month = 7;:

0000 0111 0000 0111 0000 0000 0000 0000
\_______________ year ________________/
\ month /
\_ day _/

最后,birth.day = 28;

0001 1100 0000 0111 0000 0000 0000 0000
\_______________ year ________________/
\ month /
\_ day _/

应该清楚的是,写入联合的任何成员将至少覆盖所有其他成员的一部分。

将其与结构进行对比,结构对其所有成员具有独特的存储 space,使其至少与其所有成员加在一起一样大(填充可能更大)。如果您将示例代码中所有 union 的实例替换为 struct,最后您会在内存中得到如下所示的内容:

1100 0000 0000 0111 0000 0000 0000 0000 0000 0111 0001 1100
\_______________ year ________________/ \ month / \_ day _/

每个成员的数据都完好无损,可以使用birth.yearbirth.monthbirth.day正确检索。