位域
一、基本概念
1.1 位域的概念
结构体中的冒号表示位域,如:
C
struct bit_struct
{
unsigned int bit1:10;
unsigned int bit2:8;
unsigned int bit3:14;
} data1; // sizeof data1 = 4
struct bit_struct
{
unsigned int bit1:10;
unsigned int bit2:8;
unsigned int bit3:16;
} data2; // sizeof data2 = 8
位域出现的原因是由于某些信息的「存储表示」只需要几个 bit 位就可以表示,而不需要一个完整的字节,同时也是为了节省存储空间和方便处理。
1.2 说明
-
位域必须存储在同一个类型中,不能跨类型,同时也说明位域的长度不会超过所定义类型的长度。如果一个定义类型单元里所剩空间无法存放下一个域,则下一个域应该从下一单元开始存放。
如 data2,所定义的类型是
unsigned int
类型,一共 32 位,bit1 和 bit2 用掉了 18bit,还剩下 \(32-18=14bit\),这时要存储一个 16bit 的位域元素 bit3,那么这个元素就只能从下一个unsigned int
类型的单元开始而不会在前面一个unsigned int
类型中占 14bit 后面的 unsigned int 类型中占 2bit。 -
如果位域的位域长度为0表示是个空域,同时下一个域应当从下一个字节单元开始存放。
-
使用无名的位域来作为填充和调整位置,切记该位域是不能被使用的。
-
位域的本质上就是一种结构体类型,不同的是其成员是按二进制位来分配的。
二、代码理解
C
#include <stdio.h>
#include <string.h>
struct bit_struct_1
{
unsigned int bit1:10;
unsigned int bit2:8;
unsigned int bit3:14;
} data1; // sizeof data1 = 4
struct bit_struct_2
{
unsigned int bit1:10;
unsigned int bit2:8;
unsigned int bit3:16;
} data2; // sizeof data2 = 8
/*
0001 1001 0010 1010 1011 0011 0100 1111 0101 1101 0110 1100 0111 1110 1000 1011
--------------------------- --------------------------- --------------------------- --------------------------- --------------------------- --------------------------- --------------------------- ---------------------------
19 2A B3 4F 5D 6C 8E 9B
高 <-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·-·- 低
*/
int main()
{
unsigned long long ullNum = 0x192AB34F5D6C7E8B;
memcpy(&data1, (void *)&ullNum, sizeof(data1));
memcpy(&data2, (void *)&ullNum, sizeof(data2));
printf("data1 size is %d\n", sizeof(data1)); /* size is 4 */
printf("[1] bit1 : %u\n", data1.bit1); /* 651 --> 1010001011 */
printf("[1] bit2 : %u\n", data1.bit2); /* 31 --> 00011111 */
printf("[1] bit3 : %u\n", data1.bit3); /* 5979 --> 01011101011011 */
puts("------------------------");
printf("data2 size is %d\n", sizeof(data2)); /* size is 8 */
printf("[2] bit1 : %u\n", data2.bit1); /* 651 --> 1010001011 */
printf("[2] bit2 : %u\n", data2.bit2); /* 31 --> 00011111 */
printf("[2] bit3 : %u\n", data2.bit3); /* 45903 --> 1011001101001111 */
return 0;
}
上述代码中我们定义了一个 8B 的 ullNum,其二进制表示如下图所示:
从低字节到高字节分别分配给 bit1、bit2、bit3 :