0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言中一个位域结构占多少个字节呢

冬至子 来源:Linux码农 作者:Linux码农 2022-11-16 16:44 次阅读

c语言中提供一个一种叫 “位域” 或者 “位段” 的数据结构。它的存在是为了更加的节省空间。因为在有些实际需求中,并不需要占用一个完整的字节,而只是需要一个或者几个二进制位。比如存在一个开关量时,只有 0 和 1 两种状态,只需要一个二进制位存储即可。

位域的定义如下:

struct 位域结构名{ 位域列表 };

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

例如,

struct test{
   int a:3; 
   int b:2; 
   int c:6;
};

位域的变量的说明 与结构体的方式一样,有三种方式:先定义后说明、同时定义说明、直接说明。

在声明时,位段成员必须是整形或枚举类型(通常是无符号类型)。

结构中也可以包含无名位域,作为相邻成员之间的填充或调整位置。无名位域无法被引用,它们的内容在运行时是不可预测的。

struct s{
   unsigned int a:4; //a存放结构的前4个位中 
   unsigned int :2;  // a后面的2个位填充
   unsigned int b:2;  
};

位域的定义有如下限制

1、一个位域必须存储在同一个字节中,不能跨两个字节。

比如当一个字节所剩的空间不够下一个位域存储时,则从下一个存储单元的起始位置开始存放;也可以专门让某个位域从下一个存储单元的起始位置开始。

struct s{
   unsigned int a:4; //a存放结构的前4个位中 
   unsigned int :2;  // a后面的2个位填充
   unsigned int b:6;  // 剩余的2位不够存储,从下一个存储单元开始存放
   unsigned int :0; //空位域,把该unsigned int剩余空间自动全部填充0
   unsigned int c:5; //从下一个单元存储,也即是从下一个 unsigned int 开始

}ss;

在这个位域中,a 占第一个字节的前 4 位,a 后面 2 位进行填充,第一个字节剩余的 2 位不够 b 存储,因此 b 从下一个字节开始存储,b 后面的位域填充 0,c 从下一个单元存储,该下一个单元指的是下一个 unsigned int,因为空位域 0 会把 b 后面 unsigned int 所剩的空间全部填充 0, 因此 sizeof(ss) = 8。

2、位域可以是无名域,无名域就是类似于 unsigned int : 0; 或者 unsigned int : 2; 虽然两者只是 0 和非 0 的区别,但是作用却是不同的。若无名域的位数为 0,则下一个位域将会强制从下一个单元开始(这里的一个单元指的不是下一个字节,而是跨过跨过一次数据类型的自然边界);如果无名位域为非 0,则意味着这个无名位域占着空间,不能被使用。

struct test{
   unsigned int a:3;  //a占3位
   unsigned int :0;  //对于unsigned int 类型 a 后面的剩余未全填充0
   unsigned int b:2;  //b 从下一个unsigned int 类型开始
}tt;

在该例子中 a 占 unsigned int类型所占字节的3位,a 后面的无名域会把 a 后面的所有位填充 0,因此对于 unsigned int 类型所占的 4 字节空间,除 a 的 3 位外,其他位均为0,b 从下一个 unsigned int 类型开始,所以 sizeof(tt) 为 8。

struct test{
   unsigned int a:3;  //a占3位
   unsigned int :2;  //a后面的2个位填充
   unsigned int b:2;  // b 跟着无名域后面
}tt;

a后面无名域占 2 位,b跟在无名域后面,所以 a 和 b共占用一个字节。因此sizeof(tt) 为 4。

3、如果相邻位域字段的类型相同,且其位宽之和小于类型的 sizeof 大小,则后面的字段将紧邻前一个字段存储,直到不能容纳为止 。****

struct  test {
    unsigned char a:3;
    unsigned char b:4;
} t;

a 和 b 所占的宽度之和小于 sizeof(unsigned char)大小,因此 a和b共同使用一个字节,所以 sizeof(t) 为 1;

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

struct  test {
    unsigned int a:15;
    unsigned int b:20; //从下一个unsigned int开始
} t;

由于 a 和 b 宽度之和大于 sizeof(unsigned int)大小,因此b从下一个 unsigned int 处开始,所以 sizeof(t) 为 8。

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

struct  test {
    unsigned char a : 3;
    unsigned char b : 4;
    unsigned char c : 3;
    unsigned int  d : 5;
} t;

整个结构体的总大小为 unsigned int 类型的整数倍。

6、如果相邻的位域字段的类型不同,则各编译器的具体实现有差异,VC6采取不压缩方式,Dev-C++采取压缩方式。(跟编译器有较大的关系,使用时要慎重,尽量避免)

struct  test {
    unsigned char a : 3;
    unsigned char b : 4;
    unsigned char c : 3;
    unsigned int  d : 5;
} t;

对于该类型,不压缩时,a和b类型相同会占用一个字节,c会占用一个字节,d会单独存放,不会和共占用一个字节,因为整个结构体的总大小为最宽基本类型成员大小的整数倍,因此 sizefo(t)为 8。

若压缩时(gcc下),c 和 d 共占用一个字节,因为整个结构体的总大小为最宽基本类型成员大小的整数倍,因此 sizefo(t)为 4。

7、 如果位域字段之间穿插着非位域字段,则不进行压缩;(不针对所有的编译器,跟编译器有较大的关系,使用时要慎重,尽量避免)

struct test{
    unsigned int m: 12;
    unsigned int ch;
    unsigned int p: 4;
}t;

sizeof(t) 大小为 12。

8、当使用有符号类型来定义位域,并且无意中使用到了正负(有意或者无意)特性时,可能出现不是想要的结果

struct test
{
    char a : 2;
    char b : 3;
    char c : 3;
};

struct test t;

// 位域赋值
t.a = 0x3;   // 11
t.b = 0x5;   // 101
t.c = 0x2;   // 010

printf("%d,%d,%d\\n", t.a, t.b, t.c); //结果为 -1, -3, 2

可见,当为域的最高位是 1 的时候,会进行符号扩展,而且这也取决于编译器的实现,因此,为避免此类问题,最好使用无符号类型定义位域。

9、取地址操作符 & 不能应用在位域字段上,因此不存在位域的指针。

10、位域字段不能是静态成员。

11、不能用来指定位数的类型。

若 struct 成员是指针变量类型不能用来指定所占的位数,在 64 位系统中指针固定占 8 字节,在 32 位系统中指针固定占 4 字节。

若 struct 成员是 double 或 float 类型,不能指定位数,否则编译出错,位域类型无效。

审核编辑:刘清

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7530

    浏览量

    128699
  • 编译器
    +关注

    关注

    1

    文章

    1577

    浏览量

    48614
收藏 人收藏

    评论

    相关推荐

    编程语言中一个奇怪的代码结构

    在C语言和C++等编程语言中,我们常常会遇到一个奇怪的代码结构
    发表于 11-01 10:24 220次阅读
    编程<b class='flag-5'>语言中一</b>个奇怪的代码<b class='flag-5'>结构</b>

    结构解析

    ;上例的结构定义了关于工人的信息。其中有两个位结构成员, 每个位
    发表于 03-26 10:30

    单片机c语言中定义字节怎么定义

    定义可以用***it但是定义字节?还有就是比如汇编中的DPTR的DPH和DPL在c语言中怎样定义的
    发表于 02-23 14:50

    C结构体之

    ,共个字节。其中a8
    发表于 12-10 20:35

    RS-485通信时帧数据中包含多少个字节的有效数据合适

    大家好,想问下有没有用单片机做过RS-485通信的?我现在通过自定义的RS-485协议进行多机通信,这个时候的帧协议中的有效数据为多少个字节比较合适?我看有的人说帧数据中包含的有
    发表于 04-06 09:38

    一个字节有8,也就是8bit,那么串数据如何看出是多少个字节??

    一个字节有8,也就是8bit,那么串数据如何看出是多少个字节??
    发表于 07-31 14:07

    C语言中一括号引发的……

    C语言中一括号引发的……作者:薛定谔的coding猫今天给大家带来比较典型的问题,
    发表于 05-19 14:06

    c语言中double与float的区别 相关资料分享

    的,float 占用4个字节,double 占用8个字节。%f 默认保留六小数,不足六以 0 补齐,超过六按四舍五入截断。例题圆的面积
    发表于 07-01 09:10

    为什么结构体与联合体起使用?

    /*本例程是C语言操作示例这里为什么结构
    发表于 07-14 06:23

    具有20地址和32字长的存储器能存储多少个字节的信息

    具有20地址和32字长的存储器能存储多少个字节的信息?需要多少地址作芯片选择?
    发表于 10-26 07:52

    8单片机定义 int型变量,个字节

    关注+星标公众号,不错过精彩内容作者 | strongerHuang微信公众号|嵌入式专栏首先问大家两问题:8单片机定义 int型变量,
    发表于 11-26 07:04

    是怎样去定义的

    描述存放开关量或者其他开关状态时,用一位二进位即可。为了减少嵌入式内存资源的开销,可
    发表于 12-15 07:47

    如何利用C语言操作去实现对寄存器每一位的控制

    对寄存器每一位的控制。什么是?所谓“”是把一个字节中的二进位划分为几
    发表于 02-25 06:41

    能不能在C语言中像操作寄存器那样直接操作一个字节的单独一位

       在C语言中通常操作只有真假两种状态的的数据时使用布尔bool变量比较多,如果需要同时观察多个状态,这时候选择操作效率会更高,用一个字节的8
    发表于 02-25 06:13

    c语言中段)是如何去定义的?有哪些限制

    c语言中提供种叫 “” 或者 “
    发表于 07-01 15:52