Edit2:我可以用Union做多态吗?在我看来,我可以根据自己的需要更改数据结构。
编辑:修复代码。使用 ”。”而不是“ - >”。我想问的是,如果有不同的数据类型(如int和char可以互换使用,如何确保正确存储值?由于两者具有不同的内存大小,需要更大内存空间的那个将为两者分配内存空间要分享的变量类型。
假设我有两个结构:
typedef struct a{
int a;
}aType;
typedef struct b{
char b;
}bType;
typedef union{
aType a_type;
bType b_type;
}ab;
int main(void){
ab v1;
v1.a_type.a = 5;
v1.b_type.b = 'a'
}
据我所知,aType和bType都将共享相同的内存。由于int有3个字节更大(int是4个字节,char是1个字节),因此它将有4个内存块。第一个是最左边,最后一个是最右边。我将'a'分配给v1的变量b的时间,它将保留在内存块的第一个块(最左边)。值5仍然保留在第四块内存中(最右侧)。
因此,当打印出来时,会产生垃圾值,不是吗?如果是这样,如何解决这个问题?通过这个问题,这意味着如果我将'a'存储到b_type中,共享内存必须确保仅具有该值'a',而不是之前的整数值5。
答案 0 :(得分:7)
没有正确的行为。通过一个成员设置union并从另一个成员检索值会导致未定义的行为。您可以使用此技术执行有用的操作,但它依赖于硬件和编译器。您需要考虑处理器字节顺序和内存对齐要求。
当我几乎用C编写所有编程时,有两种(便携式)技术使用了我非常依赖的联合。
标记的联合。当您需要动态类型变量时,这很好。您设置了一个包含两个字段的结构:类型判别式和所有可能类型的并集。
struct variant {
enum { INT, CHAR, FLOAT } type;
union value {
int i;
char c;
float f;
};
};
只要更改了union的值并且只检索该类型指定的值,就必须非常小心地正确设置类型值。
通用指针。由于您可以非常确定所有指针具有相同的大小和表示形式,因此您可以创建指针类型的并集,并且知道您可以交替设置和检索值,而不考虑类型:
typedef union {
void *v;
int* i;
char* c;
float* f;
} ptr;
这对于(反)序列化二进制数据特别有用:
// serialize
ptr *p;
p.v = ...; // set output buffer
*p.c++ = 'a';
*p.i++ = 12345;
*p.f++ = 3.14159;
// deserialize
ptr *p;
p.v = ...; // set input buffer
char c = *p.c++;
int i = *p.i++;
float f = *p.f++;
仅供参考:您可以让您的示例更简单。结构是不必要的。你会得到同样的行为:
int main() {
union {
int a;
char b;
} v1;
v1.a = 5;
v1.b = 'a';
}
答案 1 :(得分:1)
您描述的行为取决于平台/系统/编译器。例如,在Intel x86处理器上,5
可能是int
编译器gcc
中的第一个字节。
union
兴趣来自两个主要角度
double
和char[8]
之间的联合是获取double
结构的每个字符/字节视图的简单方法。如果使用union
没有任何好处,请不要这样做。
答案 2 :(得分:0)
解决此问题的唯一方法是跟踪存储的数据。这通常使用所谓的标记成员来完成,如下所示:
struct mystructA {
int data;
};
struct mystructB {
char data;
};
enum data_tag {
TAG_STRUCT_A,
TAG_STRUCT_B
};
struct combined {
enum data_tag tag;
union {
struct mystructA value_a;
struct mystructA value_b;
} data;
};
通过仔细跟踪您输入的数据,您可以确保稍后只读取相同的字段,从而确保您获得有意义的结果。
答案 3 :(得分:0)
如果您通过上次分配给它的同一元素访问union,则没有问题。通过访问union的char大小元素,编译器确保只返回您感兴趣的位。
编辑:人们提到了标记的工会。这是另一种风格,SDL将其用于事件结构。
enum union_tag {
STRUCT_A,
STRUCT_B
};
typedef struct {
enum union_tag tag;
int a;
} aType;
typedef struct {
enum union_tag tag;
char b;
} bType;
typedef union{
enum union_tag tag;
aType a_type;
bType b_type;
} ab;
要访问元素,您可以执行以下操作:
int result;
switch(my_union.tag){
case STRUCT_A:
result = my_union.a_type.a;
break;
case STRUCT_B:
result = my_union.b_type.b;
break;
}
答案 4 :(得分:0)
好吧,首先我们应该知道你是否正在使用Big Endian od Little Endian处理器。
Windows& Linux使用小端格式,这意味着值0x00000005实际上写为05-00-00-00,就好像你从右到左书写。
所以,第一,你把5放入一个部分,这意味着第一个字节是05,其他所有都是00。
比你将'a'放入b部分,用相应的ascii值覆盖05,即0x61。
当你看到结果数字应该是...... 97,那就是0x61的值。
union的对齐应该从头开始,但字节顺序依赖于平台。 你告诉我们在Big Endian体系结构下应该像Sun Solaris或任何Risc处理器一样正确。
我错了吗?
HTH