关于位段,对于一般的程序員来说平日用到的机会不多,因为对于一般的项目而言不会太细致的去考虑对资源的节省再节省,这次也是在看c基础编程一书时看到,而之前对于字块是完全陌生的,所以再结合一些其他网络资源做个总結。
位域是指信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域, 并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。
1.位域的声明
位域变量的声明与结构变量声明的方式相同。如:
Struct sample{
int a:7; //类型说明符位域名:位域长度
int b:2;
int c:6;
}data;
其中,data为sample变量,共占两个字节。其中位域a占第一个字节的7位,位域b占第二个字节的低2位,位域c占第二个字节的高6位。
2.位域的对齐
使用位域的主要目的是压缩存储,其大致规则为:
1) 如果相邻位域字段的类型相同且其位宽之和小于声明数据类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同但其位宽之和大于类型的sizeof大小(如:char 的位域长度不能超过8,int的字节长度不能超过32),则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;
4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。
系统会先为结构体成员按照对齐方式分配空间和填塞(padding),然后对变量进行位域操作。
位域可以有无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
Struct sample{
char a:7; //类型说明符位域名:位域长度
char b:2;
char :2;
char c:2 //无位域名的位数直接跳过且这2位不能使用
}data;
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
VC中采取不压缩方式 Dev-C++和GCC都采取压缩方式
struct A{ //结构体字节长度为8 结构体字节长度为4
char a:8; //占用第一个字节的8位 占用第一个字节的8位
unsigned int b:5; //占用第五个字节的低5位 占用第二个字节的低5位
unsigned int c:3; //占用第五个字节的高3位 占用第二个字节的高3位
};
int main()
{
char testArry[10] = "0123456789";
char testB[10] = {0};
struct A d;
memcpy(&d, testArry, sizeof(d));
printf("%d ", sizeof(d));
printf("%d ", d.a);
printf("%d ", d.b);
printf("%d ", d.c);
system("pause");
return 0;
}
VC中的
编译运行输出结果:8 48 20 1
00110111 00110110 00110101 00110100 00110011 00110010 00110001 00110000
如果将其中的unsigned int 換为 int ,則结果为:
编译运行输出结果:8 48 -12 1
00110111 00110110 00110101 00110100 00110011 00110010 00110001 00110000
gcc中的
编译运行输出结果:4 48 17 1
00110111 00110110 00110101 00110100 00110011 00110010 00110001 00110000
如果将其中的unsigned int 換为 int ,則结果为:
编译运行输出结果:4 48 -15 1
00110111 00110110 00110101 00110100 00110011 00110010 00110001 00110000
位域的实现,是编译器相关的。建议是,使用位域不要使用正负这样的特性——理论上来说,应该只关注定义的那几个bit的0或者1,是无符号的。当然,像上面那条打印也没有使用正负特性。这就是无意识的过程中使用了正负特性。可以使用无符号类型来定义位域,这样不会产生正负号这样的问题。