历史上的今天
返回首页

历史上的今天

今天是:2025年04月01日(星期二)

正在发生

2019年04月01日 | STM32 结构体位域操作 (int a:4)

2019-04-01 来源: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个字节


推荐阅读

史海拾趣

Accelink Technologies Co Ltd公司的发展小趣事

Accelink Technologies Co Ltd是一家中国领先的光通信器件和子系统供应商,以下是该公司发展的五个相关故事:

  1. 公司成立和起步阶段: Accelink Technologies Co Ltd成立于2001年,总部位于中国安徽省合肥市。公司最初专注于光通信领域的研发和生产,致力于提供高性能的光通信器件和解决方案。起步阶段,公司的产品主要包括光纤光栅、光纤耦合器、光开关等。

  2. 技术创新和产品拓展: 随着市场需求的增长和技术进步,Accelink不断进行技术创新,并逐步拓展产品线。公司推出了包括光模块、光收发器、光放大器等在内的多种光通信子系统产品,为客户提供了更全面的解决方案。

  3. 市场扩张和国际合作: Accelink积极拓展国内外市场,并与全球各地的客户建立了合作关系。公司的产品被广泛应用于光网络建设、数据中心、无线通信等领域,赢得了国内外客户的认可。同时,Accelink还与国际知名光通信企业展开合作,共同推动技术创新和市场发展。

  4. 持续投入研发和创新: Accelink不断加大研发投入,致力于技术创新和产品升级。公司设立了研发中心,拥有一支技术精湛的团队,致力于开发新产品和解决方案,满足客户不断变化的需求。同时,Accelink还与国内外高校和研究机构合作,共同推动光通信技术的发展。

  5. 未来发展展望: Accelink将继续致力于光通信技术的研发和应用,不断推出更先进、更可靠的产品和解决方案,满足客户在光网络建设和数据传输方面的需求。公司将加强国际市场拓展,拓展海外业务版图,同时不断提升自身的技术实力和市场竞争力,为光通信行业的发展做出更大的贡献。

Glow-Lite Corp公司的发展小趣事

对于红外遥控发射电路,网友可能会有多方面的问题。以下是一些可能的问题及其详细回答:

一、红外遥控发射电路的基本工作原理是什么?

回答
红外遥控发射电路的基本工作原理是,当用户按下遥控器上的某个按键时,遥控器内部的微控制器(CPU)会读取与该按键对应的二进制数据,并通过信号调理电路进行处理。随后,这些数据被调制电路转换为适合传输的信号,并经过放大后,由红外线发射二极管以红外光的形式发射出去。接收设备上的红外接收头接收到这些红外光信号后,会将其转换为电信号,并经过进一步的处理还原为原始的控制指令,从而实现遥控功能。

二、红外遥控发射电路常见的故障有哪些?

回答
红外遥控发射电路常见的故障主要包括以下几个方面:

  1. 电池电量不足或接触不良:这是最常见的故障之一,当电池电量不足或电池卡簧接触不良时,会导致遥控器无法正常工作。

  2. 按键故障:按键上的导电橡胶易磨损、老化,或按键电路中的铜箔线条断裂、开焊等,都会导致按键失灵。

  3. 振荡电路故障:振荡电路中的陶瓷谐振器易受到机械冲击而损坏,导致振荡频率偏移或停振,进而影响遥控信号的发射。

  4. 红外发光二极管故障:红外发光二极管可能因引脚开焊、内部开路或失效等原因而无法正常工作。

  5. 驱动电路故障:驱动电路中的晶体三极管、电阻等元件可能因开路、放大系数下降等原因导致故障。

  6. 编码集成电路故障:编码集成电路是整个遥控器的核心部分,其内部集成了多个复杂的电路。如果编码集成电路发生故障,将直接影响遥控信号的生成和发射。

三、如何判断红外遥控发射电路是否故障?

回答
判断红外遥控发射电路是否故障,可以采用以下几种方法:

  1. 观察指示灯:如果遥控器上有指示灯,可以通过观察指示灯是否闪亮来判断遥控器是否有红外信号发射。

  2. 替换法:用一个确认无故障的遥控器去控制同一台设备,如果控制有效,则说明原遥控器可能存在故障。

  3. 万用表检测:使用万用表测量遥控器电池电压、按键电阻、红外发光二极管两端电压等,以判断电路是否正常。

  4. 收音机检测:利用收音机的中频载波与遥控器振荡频率接近的特点,通过收音机接收遥控器发出的信号来判断遥控器是否具有发射能力。

四、如何维修红外遥控发射电路的故障?

回答
维修红外遥控发射电路的故障,需要根据具体的故障原因采取相应的措施。以下是一些常见的维修方法:

  1. 更换电池:如果电池电量不足或接触不良,应更换新电池或清理电池卡簧。

  2. 清洁按键:如果按键故障是由于导电橡胶磨损或灰尘等杂物造成的,可以用软布蘸无水酒精清洗按键表面。

  3. 更换元件:如果振荡电路、红外发光二极管、驱动电路或编码集成电路等元件损坏,应更换相应的元件。

  4. 焊接修复:如果电路中存在开焊、断裂等现象,应使用焊接工具进行修复。

  5. 调整电路:如果故障是由于电路参数设置不当或元件老化等原因造成的,应对电路进行调整或更换老化元件。

通过以上方法,可以有效地解决红外遥控发射电路中的常见故障。

EDAL公司的发展小趣事

为了进一步巩固市场地位和提升技术实力,EDAL公司开始通过收购和合作的方式拓展业务。公司成功收购了几家在EDA领域具有领先地位的公司,获得了更多的技术专利和市场份额。此外,EDAL公司还与其他科技公司建立了战略合作关系,共同研发新技术、新产品,推动整个EDA行业的发展。

EiKO Global LLC公司的发展小趣事

EiKO Global LLC,简称EiKO,成立于XXXX年,由一群热衷于照明科技的先驱者共同创立。公司初期专注于照明产品的研发与生产,致力于为全球用户提供高质量的照明解决方案。EiKO凭借对市场的敏锐洞察力和技术创新,迅速在北美市场崭露头角。

在创立初期,EiKO便确立了以“质量第一、客户至上”为经营理念的方针。通过引进先进的生产设备和技术,严格把控产品质量,EiKO的照明产品逐渐赢得了消费者的信赖。同时,EiKO还积极拓展市场,与多家知名企业和零售商建立了合作关系,产品销售网络遍布全球。

CTC Coils Ltd公司的发展小趣事

为了降低成本、提高效率,CTC Coils Ltd公司开始对供应链进行深度优化。公司与供应商建立了长期稳定的合作关系,实现了原材料的稳定供应和成本控制。同时,公司还引入了先进的供应链管理系统,实现了从采购、生产到销售的全流程信息化管理,提高了运营效率。

德欣(COV)公司的发展小趣事

作为一家有社会责任感的企业,德欣公司始终关注环境保护和可持续发展。公司积极推广绿色生产技术和资源循环利用方案,减少生产过程中的能源消耗和废弃物排放。同时,德欣公司还积极参与社会公益活动,为社区和环境贡献自己的力量。这些举措不仅体现了德欣公司的社会责任担当,也为其赢得了更多客户和合作伙伴的信任和支持。

问答坊 | AI 解惑

中华人民共和国行业标准-印制电路板设计技术指导文件

中华人民共和国行业标准-印制电路板设计技术指导文件。…

查看全部问答>

dB及dBm的含义转换

1、功率( W ): 相对 1 瓦( Watts )的线性水准。例如,WiFi 无线网卡的发射功率通常为 0.036W ,或者说36mW 。 2、增益( dBm ):相对 1 毫瓦( milliwatt )的比例水准。例如 WiFi 无线网卡的发射 增益 为 15.56dBm 。 两种表达方式可以互相 ...…

查看全部问答>

MedelSim和QuartusII6.0联合仿真

打开一个QuartusII工程后首先进行对其设置,如下图 Step1:Settings->EDA Tool Settings->Tool name选择ModelSim Step2:Tool name下的复选框选上,并在下面选择语言(VHDL或Verilog) Step3:在主菜单的Tools下选择Options...项 Step4:在如 ...…

查看全部问答>

深夜求救:程序太大了?

link后的信息为: 3 474 bytes of CODE memory 121 bytes of DATA memory (+ 21 absolute ) 1 796 bytes of CONST memory 烧录进去后 结果不正确 现象异常 用的是2K RAM 64K FLASH 是不是程序太大了?请教各位。…

查看全部问答>

求 AD9854 PCB空板

哪位大哥有单独AD9854的空板PCB啊,因为芯片自个有了!所以不要集成了芯片的模块(不要带有单片机集成在板子上),小弟想要购买一个板子。可加QQ:960071627…

查看全部问答>

I2C读数据问题

STM32模拟了一个I2C。 PORTB.9做SDA,发送从机地址给铁电存储器之后,发现不能收到铁电传回来的应答信号。GPIOB->IDR第九位为低电平才算应答吧,该位一直为高。 .从该口读取外部铁电存储器的时候发现,不管读到哪个存储单元,GPIOB->IDR的值 ...…

查看全部问答>

TQ2440 linux PDA 源码(adc,beep,button,colour,gps,led,输入法库)

这里提供的是TQ2440 linuxPDA源码,包括adc,beep,button,colour,gps,led,输入法库,需要的可以下载。广州天嵌提供学习源码,供嵌入式学习爱好者参考,授人以渔,共同学习。…

查看全部问答>

15分钟完美DIY:无线充电器,简单粗暴!

看别人做的无线供电,你不羡慕么?、可是复杂的电路找不到的元器件是不是打消了你的DIY的心!!别灰心今天就教你做最简单的无线输电。所谓的无线充电是指利用电磁波感应原理进行充电的设备,原理类似于变压器。在发送和接收端各有一个线圈,发送端 ...…

查看全部问答>

锤子手机用德州仪器 的OPA2604音频芯片,看看为啥?

本帖最后由 dontium 于 2015-1-23 11:09 编辑 锤子手机的参数,相信大家都清楚了,采用4.95寸1080P屏幕,高通骁龙801 2.5GHz处理器,2G Ram,eMMC 5.0闪存,后置1300万像素摄像头(索尼IMX214),前置500万像素(OV5648),采用美国德州仪器发烧级 ...…

查看全部问答>