#include <iostream> using namespace std; typedef struct bitstruct{ int b1:5; int b2:2; int b3:3; }bitstruct; union V{ struct X{ unsigned char s1:2; unsigned char s2:3; unsigned char s3:3; }x; unsigned char c; }v; struct foo4{ char a:2; char b:3; int c:1; }; void main(){ bitstruct b; cout<<"\n==============\n"; memcpy(&b,"EM",sizeof(b)); cout<<sizeof(b)<<endl; cout<<b.b1<<endl<<b.b2<<endl<<b.b3<<endl; cout<<"\n============\n"; v.c=100; printf("%d\n",v.x.s1); printf("%d\n",v.x.s2); printf("%d\n",v.x.s3); cout<<"\n============\n"; cout<<sizeof(struct foo4)<<endl;system("pause"); }
位域 :
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:
struct 位域结构名
{ 位域列表 };
其中位域列表的形式为: 类型说明符 位域名:位域长度
对于位域的定义尚有以下几点说明:
1. 一个位域必须存储在同一个字节中,不能跨两个字节。如一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:
struct bs
{
unsigned a:4
unsigned :0 /*空域*/
unsigned b:4 /*从下一单元开始存放*/
unsigned c:4
}
在这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。
2. 由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。
3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k
{
int a:1
int :2 /*该2位不能使用*/
int b:3
int c:2
};
从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。
二、位域的使用位域的使用和结构成员的使用相同,其一般形式为: 位域变量名•位域名 位域允许用各种格式输出。
main(){
struct bs
{
unsigned a:1;
unsigned b:3;
unsigned c:4;
} bit,*pbit;
bit.a=1;
bit.b=7;
bit.c=15;
分析:
struct bit
{ int a:3;
int b:2;
int c:3;
};
int main()
{
bit s;
char *c=(char*)&s;
cout<<sizeof(bit)<<endl;
*c=0x99;
cout << s.a <<endl <<s.b<<endl<<s.c<<endl;
int a=-1;
printf('%x',a);
return 0;
}
输出为什么是
4
1
-1
-4
ffffffff
因为0x99在内存中表示为 100 11 001 , a = 001, b = 11, c = 100
当c为有符合数时, c = 100, 最高1为表示c为负数,负数在计算机用补码表示,所以c = -4;同理
b = -1;
如果结构体中含有位域(bit-field),总结规则如下
1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;
2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;
4)如果位域字段之间穿插着非位域字段,则不进行压缩;
5) 结构体的总大小为结构体最宽基本类型成员大小的整数倍,且应尽量节省内存。
实例分析:
对于bitstruct是含有位域的结构体,sizeof(int)为4字节,按照规则:
首先b1占起始的5个字节, 根据含位域规则1, b2紧跟存放,b3也是紧跟存放的。
根据规则5,得到sizeof(bitstruct) = 4。
在进行内存分配的时候,首先分配bitstruct的第一个成员类型int(4字节),这四个字节的存放按照低字节存储在低地址中的原则。
int共4个字节:
第4个字节 - 第3个字节 - 第2个字节 - 第1个字节
在内存中的存放方式如下所示。
而后为b1分配5位,这里优先分配的应该是低5位,也就是第一个字节的低5位。
继而分配b2的2个字节,也就是第1个字节中紧接着的2位。
最后分配b3的3位,按照规则1、2,b3还是紧接着存放的,b3的最低位是第一个字节的最高位,高两位为第2个字节的低两位。
字符E二进制为0100 0101,字符M的二进制为0100 1101,在内存中存放如下所示:
memcpy为按位拷贝的,所以两片内存区可以直接对应上,得到
b1的二进制形式为:00101 ,高位为0,正数,5
b2的二进制形式为:10 ,高位为1,负数,取反加1,添加符号,-2
b3的二进制形式为:b3的最低一位是0,高位为01,拼接后为010,正数,2
对于第二个结构:
100对应的二进制: 11000100
存入内存如图:
高地址 |_1__|_1__|__0_|__0_|_0__|__1_|_0__|__0_| 低地址
| s3 | s2 | s1 |
对于第三个结构:
foo4 按照int对齐
参考:http://blog.chinaunix.net/space.php?uid=257516&do=blog&cuid=1900877
http://www.cnblogs.com/alex-tech/archive/2011/03/24/1993856.html#2176002