何时应该使用工会?为什么我们需要它们?
很难想象在什么情况下需要这种类型的灵活结构,也许在消息协议中,您将发送不同大小的消息,但即使在那种情况下,可能还有更好、更适合程序员的替代方案。
联合体有点像其他语言中的变体类型 - 它们一次只能容纳一件事情,但这件事情可以是 int、float 等,具体取决于您如何声明它。
例如:
typedef union MyUnion MYUNION;
union MyUnion
{
int MyInt;
float MyFloat;
};
MyUnion只会包含int或float,取决于你最近设置的是哪个。所以进行以下操作:
MYUNION u;
u.MyInt = 10;
现在,您持有一个等于10的整数(int);
u.MyFloat = 1.0;
现在,你拥有一个等于1.0的浮点数。它不再是整数。显然,如果你尝试执行printf("MyInt=%d", u.MyInt);,那么你可能会遇到错误,虽然我不确定具体的行为。
联合体的大小由其最大字段的大小决定,在本例中为浮点数。
sizeof(int) == sizeof(float)
(== 32
)通常是成立的。 - Nick T在学校里,我使用联合体(unions)如下:
typedef union
{
unsigned char color[4];
int new_color;
} u_color;
我使用它来更轻松地处理颜色,而不是使用 >> 和 << 运算符,我只需要遍历我的字符数组的不同索引。
当你想要模拟由硬件、设备或网络协议定义的结构,或者创建大量对象并希望节省空间时,可以使用联合。但实际上,在95%的情况下,你并不需要它们,最好使用易于调试的代码。
struct x {int x_mode; int q; float x_f};
struct y {int y_mode; int q; int y_l};
struct z {int z_mode; char name[20];};
anyPointer
是否与结构成员相对应,那么编译器如何检查您帖子中的“仅当类型和偏移量匹配时才具有相同名称的成员”的条件呢? - Herdsmanp->foo
的精确行为取决于foo
的类型和偏移量。从本质上讲,p->foo
是*(typeOfFoo*)((unsigned char*)p + offsetOfFoo)
的简写形式。至于你后面的问题,当编译器遇到一个结构体成员定义时,它要求不存在具有该名称的成员,或者该名称的成员具有相同的类型和偏移量;如果存在不匹配的结构体成员定义,我猜想编译器会报错,但我不知道它如何处理错误。 - supercat联合体很棒。我见过联合体的一个巧妙用法是在定义事件时使用它们。例如,您可能决定一个事件是32位。
现在,在这32位中,您可能想将前8位指定为事件发送者的标识符...有时您会将整个事件处理,有时您会分解它并比较其组件。联合体使您能够灵活地执行这两种操作。
union Event { unsigned long eventCode; unsigned char eventParts[4]; };
在我编写嵌入式设备的代码时,我使用了union。我有一个C int,长度为16位。当我需要从/存储到EEPROM时,我需要检索高8位和低8位。因此,我使用了以下方法:
union data {
int data;
struct {
unsigned char higher;
unsigned char lower;
} parts;
};
它不需要移位,所以代码更容易阅读。
另一方面,我看到一些旧的C++ stl代码使用联合体作为stl分配器。如果您感兴趣,可以阅读sgi stl源代码。这里是其中的一部分:
union _Obj {
union _Obj* _M_free_list_link;
char _M_client_data[1]; /* The client sees this. */
};
higher
/ lower
周围加上一个分组的 struct
吗?现在两个都应该只指向第一个字节。 - Mario一个简单而非常有用的例子是....
想象一下:
你有一个uint32_t array[2]
,想要访问字节链的第三个和第四个字节。
你可以这样做:*((uint16_t*) &array[1])
。
但很遗憾,这违反了严格别名规则!
但已知的编译器允许你做以下操作:
union un
{
uint16_t array16[4];
uint32_t array32[2];
}
从技术上讲,这仍然违反了规则。但所有已知的标准都支持此用法。
union
可以方便地确定最大常量的大小。#include <stdio.h>
#include <time.h>
#define MON_1 "January"
#define MON_2 "February"
#define MON_3 "March"
#define MON_4 "April"
#define MON_5 "May"
#define MON_6 "June"
#define MON_7 "July"
#define MON_8 "August"
#define MON_9 "September"
#define MON_10 "October"
#define MON_11 "November"
#define MON_12 "December"
#define WDAY_1 "Sunday"
#define WDAY_2 "Monday"
#define WDAY_3 "Tuesday"
#define WDAY_4 "Wednesday"
#define WDAY_5 "Thursday"
#define WDAY_6 "Friday"
#define WDAY_7 "Saturday"
int main(void)
{
time_t t = time(NULL);
struct tm *t_tm = gmtime(&t);
char *t_wday[] = {
WDAY_1,
WDAY_2,
WDAY_3,
WDAY_4,
WDAY_5,
WDAY_6,
WDAY_7
},
*t_mon[] = {
MON_1,
MON_2,
MON_3,
MON_4,
MON_5,
MON_6,
MON_7,
MON_8,
MON_9,
MON_10,
MON_11,
MON_12
},
t_arr[sizeof(union {
char mon[sizeof MON_1],
mon2[sizeof MON_2],
mon3[sizeof MON_3],
mon4[sizeof MON_4],
mon5[sizeof MON_5],
mon6[sizeof MON_6],
mon7[sizeof MON_7],
mon8[sizeof MON_8],
mon9[sizeof MON_9],
mon10[sizeof MON_10],
mon11[sizeof MON_11],
mon12[sizeof MON_12];
}) + sizeof(union {
char wday[sizeof WDAY_1],
wday2[sizeof WDAY_2],
wday3[sizeof WDAY_3],
wday4[sizeof WDAY_4],
wday5[sizeof WDAY_5],
wday6[sizeof WDAY_6],
wday7[sizeof WDAY_7];
}) + sizeof "00 00:00:00 0000"];
sprintf(t_arr, "%s %s %d %d:%d:%d %d", t_wday[t_tm->tm_wday], t_mon[t_tm->tm_mon], t_tm->tm_mday, t_tm->tm_hour, t_tm->tm_min, t_tm->tm_sec, t_tm->tm_year + 1900);
printf("%s\n", t_arr);
}