C 关于并集和多个整数值

C 关于并集和多个整数值,c,unions,C,Unions,我进入了C,我尝试了联合。我的代码如下: #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);

我进入了C,我尝试了联合。我的代码如下:

#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;
}
#包括
结婚日期{
国际年;
炭月;
焦日;
};
int main(){
出生日期;
出生年份=1984年;
出生月份=7;
出生日=28;
printf(“%d,%d,%d\n”,birth.year,birth.month,birth.day);
//返回1820,28,28
返回0;
}
  • 1984以二进制形式写成01111000000

  • 7以二进制形式写成0110

  • 28以二进制形式写入为0001 1100


我知道,由于联合,
出生年份的值为0110001100,即1820。但是我不明白为什么
birth.month
返回值28

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

简言之,联合允许您将多种不同类型中的一种放在单个变量中。例如,假设您正在实现一个文件系统。假设您需要一个变量
current_block
,该变量可以引用超级块或数据块,分别由
struct super_block
struct data_block
定义。然后你可以做:

union block_generic{
    struct super_block;
    struct data_block;
}

union block_generic current_block;
现在,
current\u块
可以是超级块或数据块


编辑:只是想添加一个关于工会实际使用情况的快速附录。继续上面的示例,要将
current_block
视为超级块,例如,为了访问文件系统的索引节点数,您需要执行
current_block.super_block.n_索引节点
(我的意思是,您不直接处理union变量,而是指定哪个“type hat”可以说,它应该是耐用的。

union是C语言中可用的一种特殊数据类型,它允许在同一内存位置存储不同的数据类型

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


引用
C11
,第§6.7.2.1章,(重点)

联合体的大小足以容纳其最大的成员。at的值 大多数成员可以随时存储在联合对象中。指向联合对象的指针 经过适当转换的联合对象指向其每个成员(或者如果成员是位字段, 然后发送到它所在的单元),反之亦然

因此,你的期望的基础是错误的。你不能同时拥有一个工会所有成员的价值观,你只能拥有一个

此外,根据第§6.5.2.3章脚注95

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


这里,最后一个赋值,
day
恰好与
month
的大小相同,因此当您尝试读取
day
时,它返回
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;
}   
基本上,您分配一个值,所有的联合成员都会得到该值;如果它在不同的类型中有不同的表示,就这样吧


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

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

0000 0000 0000 0000 0000 0000 0000 0000
\_______________ year ________________/
\ month /
\_ day _/
让我们来了解一下您对
联合日期出生的使用情况,好吗?从
出生日期=1984;
开始,我们有(请记住x86是)

然后
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 _/
应该清楚的是,给工会的任何成员写信都会覆盖至少部分其他成员

与此相反,结构的所有成员都有唯一的存储空间,使其至少与所有成员加在一起时一样大(填充时可能会更大)。如果将示例代码中的
union
的所有实例替换为
struct
,那么最后在内存中会得到类似的结果:

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

每个成员的数据都是完整的,可以通过
birth.year
birth.month
birth.day
正确检索,我想您只能访问上次修改的值,不是吗?@SouravGhosh:这是一个棘手的问题。我将C标准解释为保证您可以对pu类型使用联合nning(比如
memcpy()
)@L.M你期望
month
包含什么?(没有双关语,但你应该提到你期望看到的内容)@EOF当然你可以,当然,只需要加倍小心,你可能会陷入陷阱。:)我之前没说的是“安全”.@SouravGhosh假设您使用的实现中,
char
相当于
无符号char
,您可以安全地访问
.month
.day
,而无需担心陷阱表示。非常感谢。我就是这么想的
0001 1100 0000 0111 0000 0000 0000 0000
\_______________ year ________________/
\ month /
\_ day _/
1100 0000 0000 0111 0000 0000 0000 0000 0000 0111 0001 1100
\_______________ year ________________/ \ month / \_ day _/