引用

  • union (共用声明和共用一变量定义)

前言

union跟struct有相似的地方,但是union又叫做联合体或共用体,也就意味着它在内存存储上会和正常的有区别。


正文

写法和结构体差不多:

1
2
3
4
union unionName{
type typename;
type typename;
};

注意:union之间的成员共享内存,也就意味着union的内存占用会根据最大的成员而定义。


No.1

首先自定义一个联合体

1
2
3
4
union hh{
short sh;
int in;
};

先给实例一个hh,然后给小的变量赋值

sizeof能看到是四个字节,也就是印证他会根据联合体里面最大的变量类型扩充。

1
2
3
4
5
union hh{
short sh;
int in;
double dou;
};

在联合体里再放一个double类型

发现结构体H的占用大小变成了8字节。

可以确定联合体的内存大小由最大成员定义


No.2

那么说联合体共享内存空间,那么给short类型变量赋值之后,int和double会不会也是跟short变量一样的值?

显然是不一样的。

乱码的情况大多是没有初始化,如果说给其他成员尝试初始化呢
但是要注意联合体的初始化有点不一样。

1
2
3
4
5
6
7
8
9
10
11
union hh{
short sh;
int in;
double dou;
};

int main(){
hh H{0};

return 0;
}

在实例化一个对象的时候直接初始化0看似没什么问题,但是由于联合体共享内存的特性,这个0初始化可能是给了第一个成员,后面的成员会不会初始化则不好说,况且不同的编译器还有一定的优化特性。

所以保守起见就手动初始化

1
2
hh H;
H.in = 0;

再手动初始化成员后,能看到

in的值变成和sh的值一样,但是这个是in初始化在前,sh赋值在后,如果调换一下位置

会发现成员的值是会根据最后一次赋值而改变。


No.3

short占用两字节,int占用四字节,如果是一个负数,在short和int下又会发生不一样的解读

1
2
3
4
5
6
7
hh H;
H.in = 0;
H.sh = -1;

std::cout << sizeof(H) << std::endl;
std::cout << H.sh << std::endl;
std::cout << H.in << std::endl;

short的 -1 原码表示 1000 0000 0000 0001,反码1111 1111 1111 1110,补码1111 1111 1111 1111,十六进制合计0xffff。无非就是表示-1或65535
但是int占四字节,0xffff在int里就不会是一个负数。


No.4

1
2
std::cout << &H.sh << std::endl;
std::cout << &H.in << std::endl;

再看地址是一样的,也就是说共享了内存地址。


匿名结构体和联合体

匿名自然就是不声明类型名称

1
2
3
4
5
union {
short sh;
int in;
double dou;
};

当然直接声明好似没什么意义,编译器也会给出报错

但是我们知道结构体能在}后面提前定义变量。

1
2
3
4
5
union {
short sh;
int in;
double dou;
}un;

un自然也能进行赋值之类的操作,但是没有复用性,下次还想实例一个un结构类型的联合体只能重新定义一个联合体在实例化就会变得很麻烦。

所以匿名联合体的场景自然是不复用的前提下,比如嵌套在某处

1
2
3
4
5
6
7
struct st{
union{
int a;
char b;
double c;
}un;
};

在这种情况下,联合体没必要复用,因为他就是结构体当中的成员,还可以给结构体节省点内存,毕竟三个成员不一定都用得上。

结构体同样能匿名,只不过使用前都得提前在后面声明一个变量

1
2
3
struct {
int a;
}st;

赋值操作也都一样的,还是那句话缺少了复用性,匿名联合体可以被嵌套在结构体了,那么匿名结构体也会有相应的嵌套场所,比如说类当中。

但是匿名的情况还算少的,所以了解个大概就行了。


结语

莫的感情~都差不多