位段介绍

来源:互联网 发布:优酷数据分析 编辑:程序博客网 时间:2024/05/23 01:10

关于位段,对于一般的程序員来说平日用到的机会不多,因为对于一般的项目而言不会太细致的去考虑对资源的节省再节省,这次也是在看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 0011010100110100   00110011 00110010 0011000100110000

如果将其中的unsigned int 換为 int ,則结果为:

编译运行输出结果:8  48  -12  1

00110111 00110110 0011010100110100   00110011 00110010 0011000100110000



 gcc中的

编译运行输出结果:4  48  17  1

00110111 00110110 00110101 00110100   00110011 0011001000110001 00110000

如果将其中的unsigned int 換为 int ,則结果为:

编译运行输出结果:4  48  -15  1

00110111 00110110 00110101 00110100   00110011 0011001000110001 00110000


  位域的实现,是编译器相关的。建议是,使用位域不要使用正负这样的特性——理论上来说,应该只关注定义的那几个bit的0或者1,是无符号的。当然,像上面那条打印也没有使用正负特性。这就是无意识的过程中使用了正负特性。可以使用无符号类型来定义位域,这样不会产生正负号这样的问题。
0 0
原创粉丝点击