位域 :

有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。位段成员必须声明为int、unsigned int或signed int类型(short char long)。

一、位域的定义和位域变量的说明位域定义与结构定义相仿,其形式为:

  1. struct 位域结构名
  2. { 位域列表 };

其中位域列表的形式为: 类型说明符 位域名:位域长度     
例如:

  1. struct bs
  2. {
  3. int a:;
  4. int b:;
  5. int c:;
  6. };

位域变量的说明与结构变量说明的方式相同。 可采用先定义后说明,同时定义说明或者直接说明这三种方式。例如:

  1. struct bs
  2. {
  3. int a:;
  4. int b:;
  5. int c:;
  6. }data;

说明data为bs变量,共占两个字节。其中位域a占8位,位域b占2位,位域c占6位。对于位域的定义尚有以下几点说明:

1. 如果一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

  1. struct bs
  2. {
  3. unsigned a:
  4. unsigned : /*空域*/
  5. unsigned b: /*从下一单元开始存放*/
  6. unsigned c:
  7. }

这个位域定义中,a占第一字节的4位,后4位填0表示不使用,b从第二字节开始,占用4位,c占用4位。

2.位域的长度不能大于数据类型本身的长度,比如int类型就能超过32位二进位。

3. 位域可以无位域名,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:     

  1. struct k
  2. {
  3. int a:
  4. int : /*该2位不能使用*/
  5. int b:
  6. int c:
  7. };

从以上分析可以看出,位域在本质上就是一种结构类型, 不过其成员是按二进位分配的。

二、位域的使用位域的使用和结构成员的使用相同,其一般形式为: 位域变量名.位域名 位域允许用各种格式输出。

  1. struct bs
  2. {
  3. unsigned a:;
  4. unsigned b:;
  5. unsigned c:;
  6. } bit,*pbit;
  7. bit.a=;
  8. bit.b=; //注意:位域的赋值不能超过该域所能表示的最大值,如b只有3位,能表示的最大数为7,若赋为8,就会出错
  9. bit.c=;
  10.  
  11. printf("%d,%d,%d/n",bit.a,bit.b,bit.c);
  12. pbit=&bit;
  13. pbit->a=;
  14. pbit->b&=;
  15. pbit->c=;
  16. printf("%d,%d,%d/n",pbit->a,pbit->b,pbit->c);

上例程序中定义了位域结构bs,三个位域为a,b,c。说明了bs类型的变量bit和指向bs类型的指针变量pbit。这表示位域也是可以使用指针的。

程序的9、10、11三行分别给三个位域赋值。( 应注重赋值不能超过该位域的答应范围)程序第12行以整型量格式输出三个域的内容。第13行把位域变量bit的地址送给指针变量pbit。第14行用指针 方式给位域a重新赋值,赋为0。第15行使用了复合的位运算符"&=", 该行相当于: pbit->b=pbit->b&3位域b中原有值为7,与3作按位与运算的结果为3(111&011=011,十进制值为 3)。同样,程序第16行中使用了复合位运算"=", 相当于: pbit->c=pbit->c1其结果为15。程序第17行用指针方式输出了这三个域的值。

我们再来看看下面两个结构体定义:

  1. struct foo2 {
  2. char a : ;
  3. char b : ;
  4. char c : ;
  5. };
  6.  
  7. struct foo3 {
  8. char a : ;
  9. char b : ;
  10. char c : ;
  11. };

我们来打印一下这两个结构体的大小,我们得到的结果是:
sizeof(struct foo2) = 1
sizeof(struct foo3) = 2
显然都不是我们期望的,如果按照正常的内存对齐规则, 这两个结构体大小均应该为3才对,那么问题出在哪了呢?首先通过这种现象我们可以肯定的是:带有'位域'的结构体并不是按照每个域对齐的,而是将一些位域 成员'捆绑'在一起做对齐的。以foo2为例,这个结构体中所有的成员都是char型的,而且三个位域占用的总空间为6 bit < 8 bit(1 byte),这时编译器会将这三个成员'捆绑'在一起做对齐,并且以最小空间作代价,这就是为什么我们得到sizeof(struct foo2) = 1这样的结果的原因了。再看看foo3这个结构体,同foo2一样,三个成员类型也都是char型,但是三个成员位域所占空间之和为9 bit > 8 bit(1 byte),这里位域是不能跨越两个成员基本类型空间的,这时编译器将a和b两个成员'捆绑'按照char做对齐,而c单独拿出来以char类型做对齐, 这样实际上在b和c之间出现了空隙,但这也是最节省空间的方法了。我们再看一种结构体定义:

  1. struct foo4 {
  2. char a : ;
  3. char b : ;
  4. int c : ;
  5. };

在foo4中虽然三个位域所占用空间之和为6 bit < 8 bit(1 byte),但是由于char和int的对齐系数是不同的,是不能捆绑在一起,那是不是a、b捆绑在一起按照char对齐,c单独按照int对齐呢?我们 打印一下sizeof(struct foo4)发现结果为8,也就是说编译器把a、b、c一起捆绑起来并以int做对齐了。就是说不够一个类型的size时,将按其中最大的那个类型对齐。此 处按int对齐。

C99规定int、unsigned int和bool可以作为位域类型,但编译器几乎都对此作了扩展,
允许其它类型类型的存在。
使用位域的主要目的是压缩存储,其大致规则为:

  1. 1) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止
  2. 2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;
  3. 3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++,GCC采取压缩方式;
  4. 4) 如果位域字段之间穿插着非位域字段,则不进行压缩;
  5. 5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。
  1. struct s1
  2. {
  3. int i: ;
  4. int j: ;
  5. int a: ;
  6. double b;
  7. };
  8.  
  9. struct s2
  10. {
  11. int i: ;
  12. int j: ;
  13. double b;
  14. int a:;
  15. };
  16.  
  17. printf("sizeof(s1)= %d/n", sizeof(s1));
  18. printf("sizeof(s2)= %d/n", sizeof(s2));
  19. result: ,

第一个结构体中,i,j,a共占15个位,不足8个字节,按double 8字节对齐,共16字节

第二个结构体中,i,j共占12位,不足8字节,按8字节对齐,a也按8字节对齐,加上double共8+8+8=24个字节

C 结构体位域的更多相关文章

  1. 关于牛客网C语言结构体位域(bit-fields)的一道题

    题目链接地址: https://www.nowcoder.com/questionTerminal/f4e20747a2dd4649bac0c028daa234f4 来源:牛客网 低地址字节 Byte ...

  2. 字节序转换与结构体位域(bit field)值的读取

    最近又遇到了几年前遇到的问题,标记一下. 对于跨字节位域(bit field)而言,如果数据传输前后环境的字节序不同(LE->BE,BE->LE),简单地调用(ntohs/ntohl/ht ...

  3. 字节序转换与结构体位域(bit field)值的读取 Part 2 - 深入理解字节序和结构体位域存储方式

    上一篇文章讲解了带位域的结构体,在从大端机(Big Endian)传输到小端机(Little Endian)后如何解析位域值.下面继续深入详解字节序,以及位域存储的方式. (1) 我们知道,存储数字时 ...

  4. C语言结构体--位域

    有些数据在存储时并不需要占用一个完整的字节,只需要占用一个或几个二进制位即可.比如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位.正是基于这种考虑,C语言又提供了一种叫做位域 ...

  5. C语言笔记 08_函数指针&回调函数&字符串&结构体&位域

    函数指针 函数指针是指向函数的指针变量. 通常我们说的指针变量是指向一个整型.字符型或数组等变量,而函数指针是指向函数. 函数指针可以像一般函数一样,用于调用函数.传递参数. 函数指针变量的声明: / ...

  6. c语言学习笔记 - 结构体位域

    在学习结构体的时候遇到了位域这个概念,位域主要是为了节省内存空间,比如用一个32位,4个字节的int存储一个开关变量时,会造成空间浪费,于是干脆就考虑在这个32划分不同的区域来存储数据,例如划出1位存 ...

  7. C语言结构体位域

    demo: typedef struct { int a:2; int b:2; int c:1; }test; int main() { test t; t.a=1; t.b=3; t.c=1; / ...

  8. 全面总结sizeof的用法(定义、语法、指针变量、数组、结构体、类、联合体、位域位段)

    一.前言 编译环境是vs2010(32位). <span style="font-size:18px;">#include<iostream> #inclu ...

  9. C结构体之位域(位段)

    C结构体之位域(位段) 有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位.例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可.为了节省存储空间,并使处理简便,C ...

随机推荐

  1. GJM : Unity3D - NetWork - Hight Level API ( HLAPI) [转载]

    介绍在本系列教程中,我们将使用的网络高级API(HLAPI)来构建一个小型的多人网络案例.即使我们的例子很简单,但也会涵盖以下关键概念,这应该可以帮助大家使用HLAPI构建大型游戏项目. 在第一部分, ...

  2. IIS 7 托管管道模式 经典模式(Classic) 集成模式(Integrated) 分析与理解

    IIS 7.0 支持两种管道模式:一种是IIS 7.0最新提供的集成管道模式,另一种是经典管道模式,经典管道模式是由先前版本的IIS提供的. 我们可以通过应用程序池设置管道模式,这项功能对IIS管理员 ...

  3. 一行代码调用实现带字段选取+条件判断+排序+分页功能的增强ORM框架

    问题:3行代码 PDF.NET是一个开源的数据开发框架,它的特点是简单.轻量.快速,易上手,而且是一个注释完善的国产开发框架,受到不少朋友的欢迎,也在我们公司的项目中多次使用.但是,PDF.NET比起 ...

  4. padding下中英文左右两端对齐

    <!DOCTYPE html> <html> <head> <meta charset='UTF-8'> <title>helo</t ...

  5. CSS的简介

    CSS(Cascading Style Sheets):层叠样式表 层叠:一层一层的 样式表:有很多的属性和属性值 css将网页内容和显示样式进行分离,提高了显示功能 CSS通常被称为CSS样式表或层 ...

  6. Electron笔记

    一个能让你用Web技术开发桌面应用的开源项目.这里做一个笔记(非正式文章): 官网地址:http://electron.atom.io/ API相关 Electron提供的主进程接口.渲染进程接口.共 ...

  7. jQuery 重要的知识点归纳

    jQuery 对象 jQuery 对象就是通过 jQuery 包装 DOM 对象后产生的对象. jQuery 对象是 jQuery 独有的. 只有 jQuery 对象才能使用 jQuery 的方法,在 ...

  8. ie8不兼容rgba的解决

    借鉴................. 在调试ie8兼容性的问题时,发现ie8不支持rgba. 关于rgba(),即为颜色设置的方法函数,rgb代表颜色,a代表透明度. 如rgba(0,0,0,0.1 ...

  9. 使用powershell部署WSP包

    代码如下,先卸载,然后删除,然后添加,然后安装. 卸载之后会重启IIS,所以等待几秒钟,直到卸载完成. 添加snapin $snapin = Get-PSSnapin | Where-Object { ...

  10. 安卓开发基础之tween动画基本使用,代码教学

    xml代码块: <?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:andro ...