参考链接  https://blog.csdn.net/yanbober/article/details/8697967  https://blog.csdn.net/Tommy_wxie/article/details/43529407

  我们都知道信息的存取在高级语言中最小是Byte,以字节为单位的,虽然C语言提供了位操作符&,|,~,<<   >>可以对一个整数进行位操作,但是并没有对内存进行优化。现实生活中我们常常需要一个标志值或者假,即可以用二进制0或者1表示,这种情况很常见,如开关,过程控制、参数检测或数据通信领域时,控制信息往往只占一个字节中的一个或几个二进制位,基于此,C语言支持位域定义可以帮我们解决这个问题。

  C语言允许在结构体(联合体)中以位为单位来指定其成员变量所占的内存单元,这种以位为单位的成员称为“位段”或称“位域”( bit field) 。利用位段能够用较少的位数存储数据。位段(bit-field)是以位为单位来定义结构体(或联合体)中的成员变量所占的空间。含有位段的结构体(联合体)称为位段结构。采用位段结构既能够节省空间,又方便于操作。

定义:

位域定义与结构定义相仿,其形式为:
struct 位域结构名
{ 位域列表 };
其中位域列表的形式为: 类型说明符 位域名:位域长度

type [var]:digits

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

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

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字节);否则其他任何情况下,一个位段结构所占的空间至少是一个位段存储单元的大小;

下面以具体例子来讲解:

#include <stdio.h>
#include <iostream>
using namespace std; typedef struct{
unsigned int a:1; //存在一个非0位的位段,则至少占4Byte,注意是至少
}s;
typedef struct {
unsigned _int64 a:33; //这个占8字节
}ss;
typedef struct {
unsigned int :0; //存在一个0位的位段,C编译器占0字节,C++编译器占1字节
}s1;
typedef struct {
unsigned int a:1;
unsigned :0; //下一个位段放在一个新的位段存储单元 ,所以占4+4=8Byte
unsigned int b:2;
}s2;
typedef struct {
unsigned int a:4;
unsigned int b:32; //由于4+32》32,所以b放在一个新的位段中 4+4=8字节
}s3;
typedef struct {
unsigned int a:1;
char b; //这个加起来总共不超过4字节,占一个位段
int c:1;
int d:2;
unsigned int e:2;
}S4;
extern int testBit()
{
S4 s4;
s4.a=1;
s4.b='a';
s4.c=1;
s4.d=2;
s4.e=2;
cout<<s4.a<<"\t"<<s4.b<<"\t"<<s4.c<<"\t"<<s4.d<<"\t"<<s4.e<<endl;
printf("sizeof(s)=%d\nsizeof(s1)=%d\nsizeof(s2)=%d\nsizeof(s3)=%d\nsizeof(s4)=%d\n",
sizeof(s),sizeof(s1),sizeof(s2),sizeof(s3),sizeof(s4));
cout<<sizeof(ss)<<endl;
return 0;
}

  

以下链接是一个不错的练习体

http://its.nbtvu.net.cn/xhyu/cai_c/c_web/c/c8/c83.htm

下一篇介绍位段在0_1背包中的蛮力法应用案例

C语言位域——精妙使用内存的更多相关文章

  1. C语言位域

    转载自 http://tonybai.com/2013/05/21/talk-about-bitfield-in-c-again/ 再谈C语言位域 五 21 bigwhite技术志 bitfield, ...

  2. C语言编程程序的内存如何布局

    重点关注以下内容: C语言程序在内存中各个段的组成 C语言程序连接过程中的特性和常见错误 C语言程序的运行方式 一:C语言程序的存储区域 由C语言代码(文本文件)形成可执行程序(二进制文件),需要经过 ...

  3. C语言编程程序的内存怎样布局

    在c语言中,每一个变量和函数有两个属性:数据类型和数据的存储类别. C语言中局部变量和全局变量变量的存储类别(static,extern,auto,register) 1. 从变量的作用域划分变量(即 ...

  4. C语言之数据在内存中的存储

    C语言之数据在内存中的存储 在我们学习此之前,我们先来回忆一下C语言中都有哪些数据类型呢? 首先我们来看看C语言中的基本的内置类型: char //字符数据类型 short //短整型 int //整 ...

  5. C语言 结构体的内存对齐问题与位域

    http://blog.csdn.net/xing_hao/article/details/6678048 一.内存对齐 许多计算机系统对基本类型数据在内存中存放的位置有限制,它们会要求这些数据的首地 ...

  6. 解析C语言结构体对齐(内存对齐问题)

    C语言结构体对齐也是老生常谈的话题了.基本上是面试题的必考题.内容虽然很基础,但一不小心就会弄错.写出一个struct,然后sizeof,你会不会经常对结果感到奇怪?sizeof的结果往往都比你声明的 ...

  7. c语言位域的使用注意事项——数据溢出

    c语言可以使用位域来节省变量的空间,例如开关只有通电和断电两种状态,用 0 和 1 表示足以,也就是用一个二进位.位域的取值范围非常有限,数据稍微大些就会发生溢出,这个字使用keil的使用,keil提 ...

  8. 【C】C语言位域(位段)详解

    作者:李春港 出处:https://www.cnblogs.com/lcgbk/p/14215449.html 目录 一.位域是什么? 二.位域的存储 2.1 相邻成员的类型相同 2.2 相邻成员的类 ...

  9. C语言再学习之内存对齐

    昨天看Q3的代码,看到有个_INTSAIZEOF的宏,着实晕了一阵.一番google后,终于明白,这个宏的作用是求出变量占用内存空间的大小,先看看_INTSAIZEOF的定义吧: #define _I ...

随机推荐

  1. 解题:AHOI2017/HNOI2017 礼物

    题面 先不管旋转操作,只考虑增加亮度这个操作.显然这个玩意的影响是相对于$x,y$固定的,所以可以枚举增加的亮度然后O(1)算出来.为了方便我们把这个操作换种方法表示,只让一个手环改变$[-m,m]$ ...

  2. 线程属性API

    数据类型:pthread_attr_t 操作API: // 初始化线程属性 int pthread_attr_init(pthread_attr_t *attr);// 初始化为系统支持的所有属性的默 ...

  3. 一个最简单的使用Entity Framework 查询SQL 数据库的例子

    1.ADO.NET 3.5 Entity Framework是随着.net framework 3.5一起发布的,确认开发环境版本是大于等于3.5版本 2.确认已经安装了ADO.NET 3.5 Ent ...

  4. P1558 色板游戏

    P1558 色板游戏 题目背景 阿宝上学了,今天老师拿来了一块很长的涂色板. 题目描述 色板长度为L,L是一个正整数,所以我们可以均匀地将它划分成L块1厘米长的小方格.并从左到右标记为1, 2, .. ...

  5. 科学计算三维可视化---TraitsUI(配置视图)

    配置视图 模态窗口: from traits.api import HasTraits,Int,Strclass ModelManager(HasTraits): model_name = Str c ...

  6. snprintf()解析

    snprintf(ssid_mac,sizeof(ssid_mac),"%s_%02X%02X",ssid,macval[4],macval[5]); ssid_mac = ssi ...

  7. COGS 513 八

    513. 八 http://www.cogs.pro/cogs/problem/problem.php?pid=513 ★☆   输入文件:eight.in   输出文件:eight.out   简单 ...

  8. 搭建SVN+APACHE环境

    项目需求 根据开发需求,建立svn环境,同时建立source.bd分支,source分支所有人都能访问,bd分支管理员kazihuo可访问.同时,在此基础上构建apache,以便于相关人员能通过浏览器 ...

  9. Linux 常见文件及目录

    文件/etc//etc/passwd用户基本信息/etc/group用户组基本信息/etc/shadow/etc/passwd 文件的补充/etc/gshadow阴影口令套组中的组配置文件/etc/l ...

  10. openwrt的sysupgrade和factory固件的区别

    openwrt的固件一般分两种类型:factory原厂固件.sysupgrade固件 factory多了一些验证的东西,用于在原厂固件的基础上进行升级. 普通家用路由一般不是openwrt固件,如果要 ...