历史上的今天
返回首页

历史上的今天

今天是:2025年02月09日(星期日)

正在发生

2021年02月09日 | STM32 结构体位域操作 (int a:4)

2021-02-09 来源:eefocus

1、什么是位域


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


例如:


在存放一个开关量时,只有 0 和 1 两种状态, 用一位二进位即可。


为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。


所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。


每个域有一个域名,允许在程序中按域名进行操作。 


这样就可以把几个不同的对象用一个字节的二进制位域来表示。


位段成员必须声明为 int、unsigned int 或 signed int 类型(short char long)。


2、位域定义     


struct 位域结构名     

  位域列表

};

  

其中位域列表的形式为: 


类型说明符 位域名:位域长度     


例如:     


struct bs     

{     

int a:8;     

int b:2;     

int c:6;     

}; 

位域变量的说明与结构变量说明的方式相同。 


可采用先定义后说明,同时定义说明或者直接说明这三种方式。


例如:     


struct bs     

{     

int a:8;     

int b:2;     

int c:6;     

} data;   

说明data为bs变量,共占两个字节。


其中位域a占8位,位域b占2位,位域c占6位。


对于位域的定义尚有以下几点说明:     


1) 如果一个字节所剩空间不够存放另一位域时,应从下一单元起存放该位域。


也可以有意使某位域从下一单元开始。


例如:     


struct bs     

{     

unsigned a:4     

unsigned :0 /*空域*/     

unsigned b:4 /*从下一单元开始存放*/     

unsigned c:4     

}     

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


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


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


struct k     

{     

int a:1     

int :2 /*该2位不能使用*/     

int b:3     

int c:2     

};  

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


3、位域的使用


位域的使用和结构成员的使用相同。


其一般形式为:


位域变量名.位域名 位域允许用各种格式输出。     


struct bs     

{     

    unsigned a:1;     

    unsigned b:3;     

    unsigned c:4;     

} bit,*pbit;    

 

bit.a=1;     

bit.b=7; 

注意:位域的赋值不能超过该域所能表示的最大值,如b只有3位,能表示的最大数为7,若赋为8,就会出错   


bit.c=15;

 

printf("%d,%d,%d/n",bit.a,bit.b,bit.c);

pbit=&bit;

pbit->a=0;

pbit->b&=3;

pbit->c=1;

printf("%d,%d,%d/n",pbit->a,pbit->b,pbit->c);

上例程序中定义了位域结构bs,三个位域为a,b,c。


说明了bs类型的变量bit和指向bs类型的指针变量pbit,这表示位域也是可以使用指针的。 


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


struct foo2 {

char    a : 2;

char    b : 3;

char    c : 1;

};

 

struct foo3 {

char    a : 2;

char    b : 3;

char    c : 7;

};

我们来打印一下这两个结构体的大小,我们得到的结果是:


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之间出现了空隙,但这也是最节省空间的方法了。


我们再看一种结构体定义:


struct foo4 {

char    a : 2;

char    b : 3;

int c : 1;

};

在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) 如果相邻位域字段的类型相同,且其位宽之和小于类型的sizeof大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止;


2) 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍;


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


4) 如果位域字段之间穿插着非位域字段,则不进行压缩;


5) 整个结构体的总大小为最宽基本类型成员大小的整数倍。


struct s1 

int i: 8; 

int j: 4; 

int a: 3; 

double b; 

}; 

 

struct s2 

int i: 8; 

int j: 4; 

double b; 

int a:3; 

}; 

 

printf("sizeof(s1)= %d/n", sizeof(s1)); 

printf("sizeof(s2)= %d/n", sizeof(s2)); 

result: 16, 24 

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


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



refer:


https://www.cnblogs.com/balingybj/p/4780358.html


推荐阅读

史海拾趣

ERA Transformers公司的发展小趣事

为了保持技术领先地位和市场竞争力,ERA Transformers公司非常重视创新与研发工作。公司每年都会投入大量资金用于新产品的研发和技术创新。在一次研发项目中,公司成功开发出了一种具有超高能效和极低损耗的新型变压器。这款产品的问世立即引起了市场的广泛关注,并成功获得了多项国内外专利。持续的创新与研发使得ERA Transformers公司在电子行业中始终保持着领先地位。

芯朋微电子(chipown)公司的发展小趣事

随着技术的不断进步和市场需求的增长,芯朋微电子逐步将产品线拓展至标准电源和工业驱动领域。2013年,公司推出工控功率芯片产品,这些芯片广泛应用于电机、基站、智能电表等行业领域,进一步扩大了公司的市场份额。

EECO Switch公司的发展小趣事

为了满足全球客户的需求,EECO Switch公司积极实施全球化战略。公司在墨西哥、台湾和中国等地设立了制造工厂,并在英国剑桥设立了销售办事处。这些海外机构不仅为公司提供了更广阔的市场空间,还帮助公司更好地了解当地市场的需求和趋势。展望未来,EECO Switch将继续秉承创新、质量、服务的核心价值观,致力于成为全球领先的人机界面产品提供商。

意普(ESPE)公司的发展小趣事

意普(ESPE)公司成立于XXXX年,初期专注于光电保护技术的研发。在创始人XXX的领导下,公司凭借对光电技术的深入理解和创新,成功研发出首款红外线安全保护装置,并在行业内获得了广泛的认可。这一技术的突破不仅为公司赢得了市场份额,也为后续的发展奠定了坚实的基础。

EUPEC [eupec GmbH]公司的发展小趣事

面对未来市场的机遇和挑战,EUPEC制定了明确的发展战略。公司将继续加大技术创新和研发投入力度,推动电力半导体技术的进步和应用拓展。同时,EUPEC还将加强与国际知名企业的合作与交流,不断提升自身的竞争力和影响力。在应对市场变化和挑战的过程中,EUPEC将始终坚持以客户为中心的理念,为客户提供更优质的产品和服务。

请注意,以上故事是基于EUPEC公司的发展历程和相关信息进行概括和编写的,并非完全基于事实的直接叙述。如需更详细和准确的信息,请参考相关官方资料或新闻报道。

AKM [Asahi Kasei Microsystems]公司的发展小趣事

EUPEC一直致力于技术创新和研发,不断推动电力半导体技术的进步。在多个关键领域,EUPEC都取得了重要的技术突破,如提高电力转换效率、降低能耗等。这些技术突破不仅提升了EUPEC产品的竞争力,也为客户带来了实实在在的经济效益。同时,EUPEC还积极拓展国际市场,产品广泛应用于电解铝、高压直流输电、软启动、直流传动、高压无功补偿设备等领域。

问答坊 | AI 解惑

现在把所有的活都交给手下干,不知道是好事还是坏事

现在coding不再做了,连架构都不做了,专职于做管理还有一些客户交流以及跟公司老总的交流问题,慢慢的,很多技术上的问题就疏远了,都在担心以后技术会不会慢慢就退化了!要跳槽如果没有manager该怎么办呢…

查看全部问答>

老电子工程师十年职场感悟

当电子工程师也是十余年了,不算有出息,环顾四周,也没有看见几个有出息的!回顾工程师生涯,感慨万千,愿意讲几句掏心窝子的话,也算给咱们师弟师妹们提个醒,希望他们比咱们强! [1]职业规划很重要,好好规划自己的路,不要跟着感觉走!根据 ...…

查看全部问答>

WinCE系统中,应用层怎么获取USB设备加载事件呢?

在WinCE系统中,应用软件必须等待一个USB设备成功被加载,这个成功被加载的信息怎么才能回去到呢? 谢谢…

查看全部问答>

wince设备 MASS STORAGE问题

我们的设备上采用的是2G的NAND FLASH外加一个SD卡,三星提供的BSP和相关文档上说设备作为MASS STORAGE时,同时只能将其中一个作为MASS STORAGE连接到PC上,我们想连接PC的时候同时显示这两个存储空间,目前的候选方案是在应用程序上进行一些设置, ...…

查看全部问答>

目目目上下班

1+1=?????…

查看全部问答>

大虾帮帮忙啊,搞了好久了,还是不行...

本帖最后由 dontium 于 2015-1-23 13:26 编辑 正在做一个DSP--PCI的驱动,应用程序调试时出现如下: -----  damned.pjt - Debug  ----------------------------- [async_pci.cdb] \\"E:\\\\CCStudio_v3.1\\\\plugins\ ...…

查看全部问答>

程序问题

大家帮忙看下这个程序有些什么问题啊? 我想用这个程序测量占空比为百分之五十的方波 问什么液晶总是显示65535,而且frequency=1000000/period;这一句不管我把1000000换成多少他都显示的65535 不知道什么原因,请高手指点先谢了。   &nbs ...…

查看全部问答>

北京知名公司招聘DSP软件工程师、数据通信

DSP软件工程师 北京岗位职责:1、负责宽带无线接入系统无线系统产品物理层算法的验证及实现;2、负责无线侧基站产品物理层软件的开发及维护。任职要求:1、硕士及以上学历,电子、通信等相关专业;2、熟悉数字信号处理算法,具有良好的通信理论知识 ...…

查看全部问答>

Hanker_M4学习笔记(一)

      可能看到我帖子的人,会有些失望,这么久了才提交个led循闪烁的程序,是不太应该,其实这几天都是在看M4的驱动编程,一直在归纳总结自己在M4学习中Keil软件方面的问题,大家也许看看我的文档,就能不这么责怪我了呵 ...…

查看全部问答>

学模拟+《运算放大器噪声优化手册》读书笔记 之二

本帖最后由 dontium 于 2015-1-23 11:23 编辑 在光电二极管探测电路中,常用上述的电路,将电流转换为电压,通过学习,发现其噪声来源还真不少: 1、反馈电阻的热噪声,电阻热噪声的带宽极限为放大器的信号带宽与砖墙滤波器的矫正系数; 2、电 ...…

查看全部问答>