位域
如果程序的结构中包含多个开关量,只有 TRUE/FALSE 变量,如下:
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status;
这种结构需要 8 字节的内存空间,但在实际上,在每个变量中,只存储 0 或 1。在这种情况下,C 语言提供了一中更好的利用内存空间的方式。如果在结构内使用这样的变量,可以定义变量的宽度来告诉编译器,将只使用这些字节。例如,上面的结构可以重写成:
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status;
现在,上面的结构中,status 变量将占用 4 个字节(4*8=32位)的内存空间(unsigned int 存储大小:2 或 4 bytes,此处为2bytes),但是只有 2 位被用来存储值。如果使用了 32 个变量,每一个变量宽度为 1 位,那么 status 结构将使用 4 个字节,但只要再多用一个变量,如果使用了 33 个变量,那么它将分配内存的下一段来存储第 33 个变量,这个时候就开始使用 8 个字节。看看下面的实例来理解这个概念:
#include <stdio.h>
#include <string.h>
/* 定义简单的结构,先定义后说明 */
struct
{
unsigned int widthValidated;
unsigned int heightValidated;
} status1;
/* 定义位域结构 */
struct
{
unsigned int widthValidated : 1;
unsigned int heightValidated : 1;
} status2;
int main()
{
printf("default size of unsigned int on your computer :%d\n", sizeof(unsigned int));
printf("Memory size occupied by status1 : %d\n", sizeof(status1));
printf("Memory size occupied by status2 : %d\n", sizeof(status2));
return 0;
}
status1 的内存占用:对于 status1,它包含了两个 unsigned int 类型的成员:widthValidated 和 heightValidated。由于 unsigned int 的大小在大多数现代系统上是 4 字节(尽管这取决于编译器和平台),因此 status1 的总大小通常是 2 * 4 = 8 字节。编译器会按照 unsigned int 的自然对齐要求来分配内存,通常是 4 字节对齐,这意味着即使结构体中只有一个 unsigned int,它也会占用 4 字节。
status2 的内存占用:对于 status2,它同样包含两个成员,但这次是使用位域定义的。位域允许你指定每个成员占据的位数,而不是整个类型的大小。在你的例子中,widthValidated 和 heightValidated 都被定义为 1 位的位域。理论上,这两个位域应该只需要 2 位的存储空间。然而,由于位域通常会被打包到一个或多个整数类型的存储单元中,并且这些存储单元也需要按照它们的自然对齐方式分配内存,因此 status2 的实际大小可能会大于 2 位。
实际上,status2 的大小可能至少是一个 unsigned int 的大小(即 4 字节),因为编译器需要将这两个位域打包到一个 unsigned int 中。即使只使用了 2 位,编译器也会保留整个 unsigned int 的空间来存储这个位域结构,以简化内存访问和保持内存对齐。
因此,status1 和 status2 占用不同大小的内存主要是因为 status2 使用了位域,但位域的实际存储方式使得整个结构体仍然需要按照其成员类型的自然对齐方式(在这里是 unsigned int 的对齐方式)来分配内存。这通常意味着位域结构体的大小会向上舍入到其成员类型的最小对齐边界,而不是仅仅基于位域实际使用的位数。
当上面的代码被编译和执行时,它会产生下列结果:
default size of unsigned int on your computer :4
Memory size occupied by status1 : 8
Memory size occupied by status2 : 4D:\program\usual\vs\cdy\Debug\cdy.exe (进程 29172)已退出,代码为 0。
按任意键关闭此窗口. . .
位域声明
在结构内声明位域的形式如下:
struct
{
type [member_name] : width ;
};
下面是有关位域中变量元素的描述:
元素 | 描述 |
type | 整数类型,决定了如何解释位域的值。类型可以是整型、有符号整型、无符号整型。 |
member_name | 位域的名称。 |
width | 位域中位的数量。宽度必须小于或等于指定类型的位宽度。 |
带有预定义宽度的变量被称为位域。位域可以存储多于 1 位的数,例如,需要一个变量来存储从 0 (0000)到 7(0111)的值,可以定义一个宽度为 3 位的位域,如下:
struct
{
unsigned int age : 3;
} Age;
上面的结构定义指示 C 编译器,age 变量将只使用 3 位来存储这个值,如果试图使用超过 3 位,则无法完成。让我们来看下面的实例:
#include <stdio.h>
#include <string.h>
struct //直接说明
{
unsigned int age : 3;//定义一个宽度为 3 位的位域
} Age;
int main()
{
printf("Sizeof( Age ) : %d\n", sizeof(Age));
Age.age = 4;//0100
printf("Age.age : %d\n", Age.age);
Age.age = 7;//0111
printf("Age.age : %d\n", Age.age);
Age.age = 8;//1000//超出了位域的范围
printf("Age.age : %d\n", Age.age);
return 0;
}
当上面的代码被编译时,它会带有警告,当上面的代码被执行时,它会产生下列结果:
Sizeof( Age ) : 4
Age.age : 4
Age.age : 7
Age.age : 0D:\program\usual\vs\cdy\Debug\cdy.exe (进程 30436)已退出,代码为 0。
按任意键关闭此窗口. . .