我在C中看到了这个代码:
union time
{
long simpleDate;
double perciseDate;
} mytime;
C中的联合和结构有什么区别?你会在哪里使用工会,它有什么好处? Java,C ++和/或Python中是否有类似的构造?
答案 0 :(得分:14)
联合的行为就好像它的所有成员都在内存中的相同位置,重叠。
当您想要表示某种“通用”值或可以是任何一组类型的值时,这非常有用。由于字段重叠,因此只有在您知道之前已初始化字段时,才能合法访问该字段。尽管如此,由于C不会检查这一点,并且许多编译器都会发出允许它的代码,因此这是一个常见的技巧......有趣的类型转换,例如:
union {
int integer;
float real;
} convert;
convert.real = 3.14;
printf("The float %f interpreted as an integer is %08x", convert.real, convert.integer);
对于更加完善的用法,你可以跟踪最后存储在联合中的内容,它可能看起来像这样:
typedef enum { INTEGER = 0, REAL, BOOLEAN, STRING } ValueType;
typedef struct {
ValueType type;
union {
int integer;
float real;
char boolean;
char *string;
} x;
} Value;
请注意,union实际上是周围结构中的一个字段Value
。访问可能如下所示:
void value_set_integer(Value *value, int x)
{
value->type = INTEGER;
value->x.integer = x;
}
这记录了union的当前内容是一个整数,并存储给定的值。例如,一种功能打印Value
可以检查type
成员,并做正确的事情:
void value_print(const Value *value)
{
switch(value->type)
{
case INTEGER:
printf("%d\n", value->x.integer);
break;
case REAL:
printf("%g\n", value->x.real);
break;
/* ... and so on ... */
}
}
Java中没有相应的内容。 C ++几乎是C的超集,具有相同的功能。它甚至是“one-ups”C的实现,并允许anonymous unions。在C ++中,上面的内容可能没有命名内部联合(x
),这会使代码缩短很多。
答案 1 :(得分:11)
所以在你的例子中,当我分配时间时:
int main()
{
time t;
}
编译器可以将内存解释为& t,就好像它是long:
t.simpleDate;
或者好像它是双重的:
t.perciseDate;
所以如果t的内存的原始十六进制看起来像
0x12345678;
该值可以“解析”为double或long,具体取决于其访问方式。因此,为了使它变得有用,你必须知道如何填充长和双。在内存中格式化完全。例如,long将是一个2-s补码有符号整数,您可以阅读here。您可以了解如何在二进制here中格式化double。
然而,结构只是将单独的变量分组,将不同的地址间隔分组到一个内存块中。
(注意你的例子可能很危险,因为sizeof(long)可能是32位而sizeof(double)总是64位)
当您需要“原始”表示(如char数组)和“消息”表示时,通常会使用联合。例如,要通过套接字发送的消息:
struct Msg
{
int msgType;
double Val1;
double Val2;
}; // assuming packing on 32-bit boundary
union
{
Msg msg;
unsigned char msgAsBinary[20];
};
希望有所帮助。
答案 2 :(得分:2)
union允许您以多种不同方式解释一个内存位置(原始值,二进制值)。
我实际使用的一个例子是访问uint32的各个字节。
union {
uint32 int;
char bytes[4];
} uint_bytes;
联盟提供的是多种访问(部分)相同内存的方式。
union类型的大小等于union中最大类型的大小。
答案 3 :(得分:2)
联合是一种节省空间的方式来存储几种不同类型的“其中一种”。它没有提供重新发现存储在其中的类型的机制;这必须在线外确定。从技术上讲,在联合中访问“错误”类型(即未初始化的类型)会导致未定义的行为;在实践中,它通常会导致比特级别的演员表,并且经常被用作这样做的一种方式。
虽然“union”类型在C ++中(C ++是C的超集),但是大多数C ++类型不能安全地存储在一个中(具体来说,一个联合只能容纳POD types,即具有默认复制构造函数的类,默认析构函数,没有虚方法)。如果你想要一个节省空间,基于堆栈的等价于C ++中的联合,能够存储复杂的对象,试试Boost.Variant。
在其他不太关心堆栈分配的语言中,多态性可以完成联合的工作。在Java中,一切都从Object继承,因此Object *可用于表示任何对象;或者您可以使用公共超类或接口将对象集限制为支持特定操作集的对象。
在Python中,任何变量都可以包含任何对象,因此在某种意义上所有变量都是联合。您通常不需要确定存储在变量中的类型;相反,使用duck typing - 也就是说,寻找它支持的方法而不是它实现的类型/接口。
答案 4 :(得分:1)
联合可用于存储其任何一个成员,但(与结构不同)同时不超过一个。您可以将其视为包含足够的空间来存储其最大的成员,并为您实际分配值的成员重新使用相同的存储空间。
C ++也有工会。 Java没有。 Python中的对象成员与C完全不同,它们存储在字典中而不是在内存中连续布局。我不知道Python是否有一些方便的库类,它有点像联合,但它不像C语言那样对象的基础。
答案 5 :(得分:1)
对于一个结构,每个数据项都有自己的内存位置,但是对于联合,一次只使用一个项,为每个项分配的内存在共享内存中。联合的数据项只共享一个内存位置。联合的大小将是最大变量的大小。
这可能是有益的,因为有时我们可能不需要复杂数据结构的所有(相关)数据项的数据,并且一次只能存储/访问一个数据项。联盟在这种情况下提供帮助。
答案 6 :(得分:1)
一次只能使用一个union的一个成员,而不像struct所有成员一起驻留在内存中。因为union空间被分配了它包含的最长元素的大小。