位结构

142 篇文章 0 订阅
 

位结构

分类: C/C++   183人阅读  评论(0)  收藏  举报

位结构是一种特殊的结构, 在需按位访问一个字节或字的多个位时, 位结构 比按位运算符更加方便。


位结构定义的一般形式为: 

struct位结构名{ 
        数据类型 变量名: 整型常数; 
        数据类型 变量名: 整型常数; 
} 位结构变量;

其中: 数据类型必须是int(unsigned或signed)。 

          整型常数必须是非负的整 数, 范围是0~15, 表示二进制位的个数, 即表示有多少位。

          变量名是选择项, 可以不命名, 这样规定是为了排列需要。

例如: 下面定义了一个位结构。 
struct{ 
          unsigned incon: 8; /*incon 占用低字节的0~7共8位*/ 
          unsigned txcolor: 4;/*txcolor 占用高字节的0~3位共4位*/ 
          unsigned bgcolor: 3;/*bgcolor占用高字节的4~6位共3位*/ 
          unsigned blink: 1; /*blink占用高字节的第7位*/ 

}ch;

位结构成员的访问与结构成员的访问相同。 
例如: 访问上例位结构中的bgcolor成员可写成: 
          ch.bgcolor 

注意: 
1. 位结构中的成员可以定义为unsigned, 也可定义为signed, 但当成员长度为1时, 会被认为是unsigned类型。因为单个位不可能具有符号。 
2.  位结构中的成员不能使用数组和指针, 但位结构变量可以是数组和指针, 如果是指针, 其成员访问方式同结构指针。 
3.  位结构总长度(位数), 是各个位成员定义的位数之和, 可以超过两个字节。 
4. 位结构成员可以与其它结构成员一起使用。 


例一:写出下列程序在X86上的运行结果。
struct mybitfields
{
unsigned short a : 4;
unsigned short b : 5;
unsigned short c : 7;
}test;

void main(void) 
{
int i;
test.a=2;
test.b=3;
test.c=0;
i=*((short *)&test);
printf("%d ",i);
}
这个题的为难之处呢,就在于前面定义结构体里面用到的冒号,如果你能理解这个符号的含义,那么问题就很好解决了。这里的冒号相当于分配几位空间,也即在定义结构体的时候,分配的成员a 4位的空间, b 5位,c 7位,一共是16位,正好两个字节。下面画一个简单的示意:
变量名 位数
test     15 14 13 12 11 10 9 |8 7 6 5 4 |3 2 1 0
test.a                                  |                 |0 0 1 0
test.b                                  |0 0 0 1 1 |
test.c                0 0 0 0 0 0 0 |                 |
在执行i=*((short *)&test); 时,取从地址&test开始两个字节(short占两个字节)的内容转化为short型数据,即为0x0032,再转为int型为0x00000032,即50。输出的结果就是50。当然,这里还涉及到字节及位的存储顺序问题,后面再说。

例二:在定义位结构成员时,必须指定数据类型,这个数据类型在位结构体占用多少内存时也起到不少的作用。

举个例子:
struct mybitfieldA{
char a:4;
char b:3;
}testA;

struct mybitfieldB{
short a:4;
short b:3;
}testB;
这里,testA占用一个字节,而testB占用两个字节。知道原因了吧。在testA中,是以char来定义位域的,char是一个字节的,因此,位域占用的单位也按字节做单位,也即,如果不满一个字节的话按一个字节算(未定义的位按零处理)。而在testB中,short为两个字节,所以了,不满两个字节的都按两个字节算(未定义位按零处理)

例三:不考虑边界对齐,sizeof(A)=?
struct A 

char t:4; 
char k:4; 
unsigned short i:8; 
unsigned long m; 

sizeof(A)=7

关于位结构体在内存中的存储问题

在C结构体中,如果一个位域A在另一个位域B之前定义,那么位域A将存储在比B小的位地址中。
如果一个位域有多个位时,各个位的排列顺序通常是按CPU的端模式(Endianess)来进行的,即在大端模式(big endian)下,高有效位在低位地址,小端模式则相反。

例四:补充说明一个关于位域与普通结构成员一起使用的问题
struct mybitfield{
char a:4;
char b:3;
char aa;
char c:1;}test;
这种情况下,test应该占几个字节呢?2个(4+3+1=8占一个字节,aa占一个)还是3个(4+3不足补一位,占一个字节,aa占一个字节,c占一个字节)?
写个小程序验证一下:
int main(int argc, char* argv[])
{
int i;
test.a = 1;
test.b = 1;
test.aa = 1;
test.c = 1;
i=*((short *)&test);
printf("%d \n",i);
return 0;
}
输出结果是273,化为十六进制数0x111,可见是按三个字节来处理了(如果按两个字节处理的话,cba组成一个字节,是10010001(十六进制0x91)再加上aa,那就应该是0x191了)。
举这个例子是为了说明一下,定义位域的话,最好是把所以有位域放在一起,这样可以节省空间(如果把c和aa换一下位置,那test就只占两个字节了)。

另外也是为了强调一下位结构体的内存分配方式,按定义的先后顺序来分配,而位域(或成员)内的字节顺序则按照CPU的位顺序来进行(一般与CPU的端模式对应)。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值