C学习笔记(6)--- 共用体,位域深入

2022-10-13,

1.共用体:

 

共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。

为了定义共用体,您必须使用 union 语句,方式与定义结构类似。

 

例子:

union data {

  int i;

  float f;

  char str[20];

} data;

 

这意味着一个变量(相同的内存位置)可以存储多个多种类型的数据。您可以根据需要在一个共用体内使用任何内置的或者用户自定义的数据类型。共用体的占用的内存大小由最大的变量决定---这个例子里面就是字符串(char str[20]),占用20个字节内存。

 

为了访问共用体的成员,我们使用成员访问运算符(.)。 但是和结构体不一样,由于共用体本质上是一个内存位置,所以会导致在同一时间里只能有一个值占用内存位置。

 

比如:

data.i = 10;

data.f = 220.5;

strcpy( data.str, "c programming");

printf( "data.i : %d\n", data.i);

printf( "data.f : %f\n", data.f);

printf("data.str : %s\n", data.str);

打印(printf)这个三个值,前两个值都会损坏,因为内存位置被赋给了str.

 

但是假如是:

 

data.i = 10;

printf( "data.i : %d\n", data.i);

data.f = 220.5;

printf( "data.f : %f\n", data.f);

strcpy( data.str, "c programming");

printf( "data.str : %s\n", data.str);

 

每次内存被占用之后都打印了出来,然后又重新赋值,所以不会造成损坏。

 

 

共用体作用:

 

节省内存,有两个很长的数据结构,不会同时使用,比如一个表示老师,一个表示学生,如果要统计教师和学生的情况用结构体的话就有点浪费了!用共用体的话,只占用最长的那个数据结构所占用的空间,就足够了!

 

共用体应用场景:

 

通信中的数据包会用到共用体:因为不知道对方会发一个什么包过来,用共用体的话就很简单了,定义几种格式的包,收到包之后就可以直接根据包的格式取出数据。

 

2.位域(深入):

 

假设我们需要一个结构体只储存一个固定长度的值(比如说 1,0 这种来代表true/false --- 0001只需要一个bit)的,如果正常去定义,需要两个 int (每个4字节 byte,一共 8 byte)。c 语言提供了一种更好的利用内存空间的方式。如果您在结构内使用这样的变量,您可以定义变量的宽度来告诉编译器,您将只使用这些字节byte。

 

定义例子:

struct {

  unsigned int widthvalidated : 1;

  unsigned int heightvalidated : 1;

} status;

 

如上,status 变量将占用 4 个字节(byte)的内存空间,但是只有 2 位(bit)被用来存储值,意思就是说这两个成员共用了一个int的内存空间(都是同类型)。

如果您用了 32 个变量,每一个变量宽度为 1 位,那么 status 结构将使用 4 个字节,但只要您再多用一个变量,如果使用了 33 个变量,那么它将分配内存的下一段来存储第 33 个变量,这个时候就开始使用 8 个字节。

 

age.age = 7;

printf( "age.age : %d\n", age.age );

age.age = 8; // 二进制表示为 1000 有四位,超出

printf( "age.age : %d\n", age.age );

 

output :

age.age : 7
age.age : 0

 

 

这个结果还会伴随着警告。

 

 

 

sub:(来自上章)

 

1.一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。

 

2.由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长,一些编译器可能会允许域的内存重叠,另外一些编译器可能会把大于一个域的部分存储在下一个字中。

 

3.位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的.

 

4.位域在本质上就是一种结构类型,不过其成员是按二进位分配的。

 

5.结构体变量的首地址能够被其最宽基本类型成员的大小所整除。

 

6.结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal adding)。即结构体成员的末地址减去结构体首地址(第一个结构体成员的首地址)得到的偏移量都要是对应成员大小的整数倍。

 

7.

超出范围并不是直接丢弃,而是保留对应的 3 位的值。

比如 8 是 00001000,按照位域,对应 3 位的值是 000,所以打印结果是 0;

但是 9 是 00001001,按照位域,对应 3 位的值是 001,所以打印结果是 1;

同理 10 是 00001010,按照位域,对应 3 位的值是 010,所以打印结果是 2;

 

 

引用:

 

《C学习笔记(6)--- 共用体,位域深入.doc》

下载本文的Word格式文档,以方便收藏与打印。