有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。

例如在存放一个开关量时,只有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.位域的对齐

如果结构体中含有位域(bit-field),那么VC中准则是:

  1) 如果相邻位域字段的类型相同且其位宽之和小于声明数据类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;

  2) 如果相邻位域字段的类型相同但其位宽之和大于类型的sizeof大小(如:char 的位域长度不能超过8,int的字节长度不能超过32),则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;

  3) 如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式(不同位域字段存放在不同的位域类型字节中),Dev-C++和GCC都采取压缩方式;

  系统会先为结构体成员按照对齐方式分配空间和填塞(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>

struct A{     //结构体字节长度为8

char a:8;          //占用第一个字节的8位

unsigned int b:5;     //占用第五个字节的低5位

unsigned int c:3;     //占用第五个字节的高3位

};

int main()

{

char testArry[10] = "0123456789";

char testB[10] = {0};

struct A d;

memcpy(&d, testArry, sizeof(d));

printf("%d ", sizeof(d));

p rintf("%d ", d.a);

printf("%d ", d.b);

printf("%d ", d.c);

system("pause");

return 0;

}

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

00110111 00110110 00110101 00110100   00110011 00110010 00110001 00110000

位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间。含有位段的结构体(联合体)称为位段结构。采用位段结构既能够节省空间,又方便于操作。

位段的定义格式为:

type  [var]: digits

其中type只能为int,unsigned int,signed int三种类型(int型能不能表示负数视编译器而定,比如VC中int就默认是signed int,能够表示负数)。位段名称var是可选参数,即可以省略。digits表示该位段所占的二进制位数。

那么定义一个位段结构可以像下面这段代码去定义:

struct node
{
unsigned int a:4; //位段a,占4位
unsigned int :0; //无名位段,占0位
unsigned int b:4; //位段b,占4位
int c:32; //位段c,占32位
int :6; //无名位段,占6位
};

一.位段的使用

使用位段需注意一下几点:

1)位段的类型只能是int,unsigned int,signed int三种类型,不能是char型或者浮点型;

2)位段占的二进制位数不能超过该基本类型所能表示的最大位数,比如在VC中int是占4个字节,那么最多只能是32位;

3)无名位段不能被访问,但是会占据空间;

4)不能对位段进行取地址操作;

5)若位段占的二进制位数为0,则这个位段必须是无名位段,下一个位段从下一个位段存储单元(这里的位段存储单元经测试在VC环境下是4个字节)开始存放;

6)若位段出现在表达式中,则会自动进行整型升级,自动转换为int型或者unsigned int。

7)对位段赋值时,最好不要超过位段所能表示的最大范围,否则可能会造成意想不到的结果。

8)位段不能出现数组的形式。

二.位段结构在内存中的存储方式

对于位段结构,编译器会自动进行存储空间的优化,主要有这几条原则:

1)如果一个位段存储单元能够存储得下位段结构中的所有成员,那么位段结构中的所有成员只能放在一个位段存储单元中,不能放在两个位段存储单元中;如果一个位段存储单元不能容纳下位段结构中的所有成员,那么从剩余的位段从下一个位段存储单元开始存放。(在VC中位段存储单元的大小是4字节).

2)如果一个位段结构中只有一个占有0位的无名位段,则只占1或0字节的空间(C语言中是占0字节,而C++中占1字节);否则其他任何情况下,一个位段结构所占的空间至少是一个位段存储单元的大小;

测试程序:

/*测试位段 201110.12*/ 
#include<iostream>
using namespace std;

typedef struct node
{
unsigned int a:1; //存在一个非0位的位段,则至少占4Byte
}S;

typedef struct node1 //在C++中占1字节的空间 ,在C中占0字节
{
unsigned int :0;
}S1;

typedef struct node2
{
unsigned int a:1;
unsigned int :0; //下一个位段放在一个新的位段存储单元 ,所以占4+4=8Byte
unsigned c:32;
}S2;

typedef struct node3
{
unsigned int a:4;
unsigned int :0;
int :6; //这个位段放在一个新的位段存储单元
unsigned c:32; //由于6+32>32,所位段c也放在一个新的位段存储单元,所以占4+4+4=12Byte
}S3;

typedef struct node4
{
unsigned int a:1;
char b; //在一个位段存储单元中能够存下所有的成员,所以占4Byte
int c:1;
int d:2;
unsigned int e:2;
}S4;

int main(int argc, char *argv[])
{
S4 s4;
s4.a=1;
s4.c=1;
s4.d=2;
s4.e=3;
printf("%d %d %d %d\n",s4.a,s4.c,s4.d,s4.e);
printf("%d %d %d %d %d\n",sizeof(S),sizeof(S1),sizeof(S2),sizeof(S3),sizeof(S4));
return 0;
}

执行结果为:

1 -1 -2 3
4 1 8 12 4
请按任意键继续. . .
当打印s4的各个位段时,打印的结果与赋的初始值不同。

由于c只占1位,那么没有数据位,此时进行符号扩展直接在高位添加1,所以打印的结果为-1;

由于d占2位,那么当将2赋给d时,内存中存储的内容为10,此时进行符号扩展,高位补1,则为0XFF FF FF FE,那么其真值则为-2.

C语言中的位段----解析的更多相关文章

  1. C语言中的声明解析规则——数组,指针与函数

    摘要:C语言的申明存在的最大问题是:你无法以一种人们所习惯的自然方式和从左向右阅读一个声明,在引入voliatile和const关键字以后,情况更加糟糕了.由于这些关键字只能出现在声明中,是的声明形式 ...

  2. C语言中的位段(位域)知识

    在结构体或类中,为了节省成员的存储空间,可以定义某些由位组成的字段,这些字段可以不需要以byte为单位. 这些不同位长度的字段实际存储于一个或多个整形变量.位段成员必须声明为int, signed i ...

  3. C语言中使用库函数解析命令行参数

    在编写需要命令行参数的C程序的时候,往往我们需要先解析命令行参数,然后根据这些参数来启动我们的程序. C的库函数中提供了两个函数可以用来帮助我们解析命令行参数:getopt.getopt_long. ...

  4. (转)使用 CJSON 在C语言中进行 JSON 的创建和解析的实例讲解

    使用 CJSON 在C语言中进行 JSON 的创建和解析的实例讲解   本文用代码简单介绍cjson的使用方法,1)创建json,从json中获取数据.2)创建json数组和解析json数组 1. 创 ...

  5. 001_解析go语言中的闭包

    go语言中的闭包,是大家学习go语言的一个大难点,笔者在学习时候也是痛苦不堪,在来回对比了其它语言的用法,并且查阅了很多网上的文章,终于对闭包有了一个较为清晰的认识,以下就是关于闭包的解析 首先看一个 ...

  6. 16.C语言中数据类型的本质含义是:表示一个内存格子的长度和解析方法。

    数据类型决定长度的含义:我们一个内存地址(0x30000000),本来这个地址只代表1个字节的长度,但是实际上我们可以通过给他一个类型(int),让他有了长度(4),这样这个代表内存地址的数字(0x3 ...

  7. python语言中的编码问题

    在编程的过程当中,常常会遇到莫名其妙的乱码问题.很多人选择出了问题直接在网上找答案,把别人的例子照搬过来,这是快速解决问题的一个好办法.然而,作为一个严谨求实的开发者,如果不从源头上彻底理解乱码产生的 ...

  8. 在C语言中利用PCRE实现正则表达式

    1. PCRE简介 2. 正则表达式定义 3. PCRE正则表达式的定义 4. PCRE的函数简介 5. 使用PCRE在C语言中实现正则表达式的解析 6. PCRE函数在C语言中的使用小例子 1. P ...

  9. go 语言中常用的包

    来自学习go语言.pdf 译者刑星 ==== fmt 包fmt实现了格式化IO函数,这与c的printf和scanf类似,格式化短语派生于c %v 默认格式的值.当打印结构时,加号(%+v)会增加字段 ...

随机推荐

  1. AGC036 A-Triangle | 构造

    题目链接 题意: 给出一个数$S(1\leqslant S \leqslant 10^{18})$. 要求在平面直角坐标系中找到三个点$(X_1,Y_1),(X_2,Y_2),(X_3,Y_3)$,满 ...

  2. python 模块 hashlib(提供多个不同的加密算法)

    hashlib是涉及安全散列和消息摘要,提供多个不同的加密算法借口,如SHA1.SHA224.SHA256.SHA384.SHA512.MD5等. import hashlib m = hashlib ...

  3. 非对称加密和linux上的 ssh-keygen 工具使用

    rsa :创造非对称加密的三个人名.原理是两个1024到2048之间的素数,以此为乘积.等... a*b=c  一般a*b为私钥端,c为公钥端.因为 c非常难算出a和b. ssh-keygen -t ...

  4. 分布式技术-Zookeeper概述

    概述 Zookeeper是一个开源的分布式的,为分布式应用提供协调服务的Apache项目 在大数据技术生态圈中,zookeeper(动物管理员),Hadoop(大象),Hive(蜜蜂),Pig(猪) ...

  5. 2016西邮Linux兴趣小组大事记

    2016年还有半个小时就结束了,前面把自己9月做的规划拿出来完善了下,觉得真的是不容易的一年,所有的事情只有自己经历过才会有不一样的感受,世上无难事,只怕有心人. 这是我九月份制定的计划: 下面是20 ...

  6. 【Git 系列】一个超好用的命令你会用吗?

    stash在英文意思是隐藏.git stash 的作用也是隐藏没完成的代码,防止它干扰别人或者新分支的工作. 一.背景 1.1 我们经常会遇到这样的情况 正在 dev 分支开发新功能,做到一半时有人过 ...

  7. Part 61 to 63 Talking about partial class and partial method in C#

    部分类和部分方法 部分类是用partial声明的类,它允许我们把一个类分割成两个或多个类,当应用程序编译的完成的时候,多个部分类会结合成一个类,同时partial关键字也可以用于声明结构和接口. 那么 ...

  8. 【linux系统】命令学习(二)文件处理命令

    查看帮助 1.--help     例如:ls --help  会有中文 2.man       例如:man ls   都是英文 进入手册的界面 空格键:向下翻页 回车:一行一行翻页 B:向前翻页 ...

  9. 「3dmax」快速配置3DMax

    3DMax学习 1.0.认识3dmax 3dmax(3D Studio Max),版权Autodesk公司持有.是基于PC系统的三维动画渲染和制作软件,主要用于模型构建和骨骼动画制作.行业使用分布广泛 ...

  10. [loj3284]Exercise

    对于一个排列$p_{i}$,假设循环长度依次为$x_{1},x_{2},...,x_{m}$,那么所需步数即${\rm lcm}_{i=1}^{m}x_{i}$ 由于是乘积,因此可以枚举素数$p$,并 ...