简要分析C中结构的位域成员

来源:互联网 发布:实施国家大数据战略 编辑:程序博客网 时间:2024/04/26 22:50
    C/C++提供了一个内嵌的特征来访问字节中的为,即位域。位域很有用,因为:

    1)如果存储空间受限,可以在一个字节中存储多个布尔变量(真/假)。
    2)某些设备传输被编码为一个字节中的为的状态信息。
    3) 某些加密程序需要访问字节中的位。

    C/C++使用基于结构的方法来访问位。事实上,位域是结构成员的特殊类型,它以位(bit)为单位定义域的长度。

    位域定义的一般形式如下(C++风格)

    struct struct-type-name
    {
       type name1:length;
       type name2:length;
       ....
       type nameN:length;
    } variable_list;

    type是位域的类型,应该是_Bool(C99)、char、int和枚举等整型类型。
    length是位域的长度,要求是非负整型常量或表达式,并且值不能大于type所对应的位宽度。例如,char bit_field:9是无法通过编译的。
    另外,长度为1的位域应该声明为unsigned,因为单个位不能有符号。

    给位域赋值与给其他任何类型的结构成员赋值一样。

    位域并不一定要命名,这样可以跳过无用位,方便的使用希望的位。

    位域变量的使用有一些限制:

       1).不能使用位域变量的地址。
       2).位域变量不能构成数组。
       3).位域变量不能声明为静态的。
   
    特别的,位域的使用与机器的比特序有关。

    关于比特序和字节序之间的区别和联系,可以参考下文:
    http://www.linuxjournal.com/article/6788

    我的blog上有该文的翻译版,不过本人乃业余翻译者,不对翻译内容和质量作任何承诺和保证。
    http://blog.csdn.net/lovekatherine/archive/2007/04/14/1564731.aspx


后文重点分析位域与比特序的关系,以下面的小程序为例。



   
#include <stdio.h>
#include 
<string.h>

typedef 
struct _bitdomain

{    

    unsigned 
char a:3;
    unsigned 
char b:5;

}
 X;


void display (char dst)
{
   
   
int i;
   unsigned 
int m=128;

   
while(m)
   
{
        printf(
"%u",(unsigned char)dst/m);
        dst
%=m;
        m
/=2;
   }


   printf(
",");
}


int main ()

{

  X x;
  memset ( 
&x,0x0,sizeof(x));
  

  *( unsigned
char *&x=0xb4;


  printf(
"sizf of struct X :%d "sizeof(x) );
  
  
int size=sizeof(x);
  
char * ch=(char*&x;
  
int i;

  
for(i=0;i<size;i++)
  
{     
        
    display( ch[i]);
  }

  
   
  printf(
" ");
  

  printf(
"x.a=%u ",(unsigned char )x.a);
  printf(
"x.b=%u ",(unsigned char )x.b);
  
 
  
return 1;

}




   
    运行环境:i386+ubuntu7.04+gcc4.1.2

    程序的输出结果为:
      
       x=10110100,
       x.a=100 (0x44),  
       x.b=10110(0xb),

    下面分析程序的输出:

    首先,结构X的大小为1字节。
    其次,i386架构下的字节序和比特序为小端,即高位字节(比特)存放在内存的高地址。

    可知x=0xb4在内存中的布局如下:

    bit      7   6   5   4   3   2   1   0
    value    1   0   1   1   0   1   0   0

    又根据Kevin定理#2:“在C中一个包含位域的结构中,如果位域A在位域B之前定义,那么位域A所占据的内存空间永远低于B所占用的内存空间。”
   
    可知x.a 对应位2~位0 ,x.b对应位7~位3,因此,按照高地址对应高位的关系,有

    x.a=100, x.b=10110


对上述程序进行局部修改,看看在位域长度超出8(1byte)时会是什么情形。

#include <stdio.h>
#include 
<string.h>

typedef 
struct _bitdomain

{    
    unsigned 
short y:12;
    unsigned 
short z:4;


}
 X;


void display (char dst)
{
   
   
int i;
   unsigned 
int m=128;

   
while(m)
   
{
        printf(
"%u",(unsigned char)dst/m);
        dst
%=m;
        m
/=2;
   }


   printf(
",");
}


int main ()

{

  X x;
  memset ( 
&x,0x0,sizeof(x));
  

  
*( unsigned short *&x=0x32b4;


  printf(
"sizf of struct X :%d "sizeof(x) );
  
  
int size=sizeof(x);
  
char * ch=(char*&x;
  
int i;

  
for(i=0;i<size;i++)
  
{     
        
    display( ch[i]);
  }

  
   
  printf(
" ");
  


  printf(
"x.y=%x ",(unsigned short)x.y);
  printf(
"x.z=%x ",(unsigned short)x.z);

  
  
return 1;

}


 
程序的输出结果为:
   
    x=(0x32b4)
    x.y=0x2b4
    x.z=0x3
   (其中y、z分别定义为 unsigned short y:12和unsigned short z:4)

    和前例一样,仍然从x的内存布局入手。

    (不失一般性,假设x的地址为0X1000)

addr               0x1000                            0x1001 
bit    7   6   5   4   3   2   1   0     7   6   5   4   3   2   1   0  
vlaue  1   0   1   1   0   1   0   0     0   0   1   1   0   0   1   0

    同样依据Kevin定理#2,可知x.y对应地址0x1000的8bit和0x1001的位0~位3,x.z对应地址0x1001的位4~位7。

    因此,按照高地址对应高比特和高字节的关系,可得出:         `            x.y=001010110100=0x2b4,x.z=0011=0x3

原创粉丝点击