首页 > 其他分享 >学懂C语言(二十五):深入理解 C语言结构体 位域 的概念

学懂C语言(二十五):深入理解 C语言结构体 位域 的概念

时间:2024-07-25 19:58:36浏览次数:15  
标签:struct int unsigned C语言 学懂 对齐 位域 字节

        

目录

一、位域的基本概念

二、位域的定义

三、位域的内存分配和大小计算

示例1:简单位域

示例2:跨越多个存储单元

注意事项

结构体对齐控制

总结


        C语言中的位域(Bit-Field)是一种特殊的数据结构,允许在结构体中定义占用特定位数的成员,主要用于节省存储空间并简化对特定位数数据的操作。位域一般用于需要紧凑表示某些标志(flags)或状态的场景,如硬件寄存器的模拟、协议头的解析等。以下是对C语言位域知识点的详细讲解。

一、位域的基本概念

  • 定义:位域是指把一个字节(或其他整数类型)中的二进制位划分为几个不同的区域,每个区域有不同的位数,并允许在程序中通过域名来访问这些区域。
  • 目的:通过仅占用必要的位数来存储数据,从而节省存储空间。

二、位域的定义

位域的定义与结构体的定义类似,但每个成员后面会跟随一个冒号和该成员所占的位数。定义形式如下:

struct 位域结构名 {  
    类型说明符 位域名:位域长度;  
    ...  
};
  • 类型说明符:指定了位域的类型,如intunsigned intchar等。需要注意的是,位域的类型必须是整数类型。
  • 位域名:为位域指定的名称,用于在程序中引用该位域。
  • 位域长度:指定了位域占用的位数,这个长度必须小于或等于指定类型的位宽度。

示例:

struct BitField {
    unsigned int flag : 1;
    unsigned int value : 3;
    unsigned int mode : 4;
};

在这个例子中:

  • flag 占用 1 位。
  • value 占用 3 位。
  • mode 占用 4 位。

三、位域的内存分配和大小计算

位域的内存分配和大小计算可能会因编译器和平台的不同而有所差异,但一般遵循以下原则:

  1. 相邻位域字段类型相同
    • 如果相邻位域字段的类型相同,且其位宽之和小于或等于类型的sizeof大小(注意这里是指类型的位数,而不是sizeof操作符返回的字节数),则后面的字段将紧邻前一个字段存储,直到不能容纳为止。
    • 如果相邻位域字段的类型相同,但其位宽之和大于类型的sizeof大小,则后面的字段将从新的存储单元开始,其偏移量为其类型大小的整数倍(以字节为单位,但实际对齐到的是位)。
  2. 相邻位域字段类型不同
    • 这种情况下,不同编译器的实现可能有所不同。一些编译器可能会将不同类型的位域字段存放在不同的字节中,以确保对齐和访问效率。
  3. 结构体的总大小
    • 结构体的总大小通常是其最宽基本类型成员大小的整数倍,以满足内存对齐的要求。这意味着即使所有位域成员的总位数远小于一个字节,结构体也可能占用多个字节的内存。 
示例1:简单位域
#include <stdio.h>

struct BitField {
    unsigned int flag : 1;
    unsigned int value : 3;
    unsigned int mode : 4;
};

int main() {
    printf("Size of struct BitField: %lu bytes\n", sizeof(struct BitField));
    return 0;
}

在这个例子中:

  • flag 占用 1 位。
  • value 占用 3 位。
  • mode 占用 4 位。

总共:1 + 3 + 4 = 8 位,即1字节。但是,由于unsigned int一般需要4字节对齐,编译器可能会将整个结构体对齐到4字节。

Size of struct BitField: 4 bytes
示例2:跨越多个存储单元
#include <stdio.h>

struct BitField {
    unsigned int a : 1;
    unsigned int b : 15;
    unsigned int c : 17;
};

int main() {
    printf("Size of struct BitField: %lu bytes\n", sizeof(struct BitField));
    return 0;
}

在这个例子中:

  • a 占用 1 位。
  • b 占用 15 位。
  • c 占用 17 位。

总共:1 + 15 + 17 = 33 位。由于unsigned int一般是4字节(32位),所以需要两个unsigned int存储。

Size of struct BitField: 8 bytes
注意事项
  1. 内存对齐:编译器可能会为满足硬件对齐要求而进行填充,这会影响结构体的大小。
  2. 平台相关性:不同编译器和不同硬件平台可能会对位域的大小和对齐方式有不同的处理方式。
  3. 跨平台兼容性:由于上述差异,位域在不同平台上的兼容性可能存在问题,需要小心处理。
  4. 性能考虑:尽管位域可以节省内存,但在某些平台上,操作位域的性能可能会较低,因为这些操作可能需要额外的指令来处理位操作。

为了确保结构体的大小符合预期,可以使用#pragma pack或其他编译器指令来控制对齐方式,但这需要根据具体情况谨慎使用。

结构体对齐控制

使用#pragma pack可以控制结构体的对齐方式,以确保结构体大小符合预期。

#include <stdio.h>

#pragma pack(push, 1)
struct PackedBitField {
    unsigned int flag : 1;
    unsigned int value : 3;
    unsigned int mode : 4;
};
#pragma pack(pop)

int main() {
    printf("Size of struct PackedBitField: %lu bytes\n", sizeof(struct PackedBitField));
    return 0;
}

在这个例子中,我们使用#pragma pack(push, 1)来将结构体对齐到1字节。

Size of struct PackedBitField: 1 bytes

这样可以确保结构体大小为1字节,且没有额外的填充位。

总结

C语言的位域是一种强大的数据结构,可以帮助开发者在节省存储空间的同时,方便地操作特定位数的数据。然而,由于编译器和平台的差异,位域的内存分配和大小计算可能会变得复杂。因此,在使用位域时,需要仔细考虑这些因素,并确保代码的可移植性和健壮性。

标签:struct,int,unsigned,C语言,学懂,对齐,位域,字节
From: https://blog.csdn.net/martian665/article/details/140698007

相关文章

  • C语言:字符串函数、内存函数剖析
    字符串函数、内存函数剖析一、字符串函数(一)求字符串长度1、strlen(1)库函数实现(2)自定义实现(二)长度不受限制的字符串函数1、strcpy(1)库函数实现(2)自定义实现2、strcat(1)库函数实现(2)自定义实现3、strcmp(1)库函数实现(2)自定义实现(三)长度受限制的字符串函数介绍1、strncpy2、s......
  • 随记0000——从0、1 到 C语言
    C语言的发展历程是计算机科学史上的一个重要里程碑。下面是从最早的机器语言到汇编语言,再到高级语言如C语言的简化演进过程:1.机器语言定义与特点机器语言是最底层的编程语言,由一系列二进制代码组成。直接被CPU执行,无需转换或编译。难以阅读、编写和维护。2.汇编语......
  • 2个月搞定计算机二级C语言——真题(2)解析
    1.前言大家好,我是梁国庆。本篇博客讲解真题2,其中的填空题用到了指向结构体的指针访问被指结构体的成员的知识,我在下文做了讲解。其他的主要还是对数组的考察,没什么难度,搞清楚思路写程序就可以。2.程序填空题2.1题目要求2.2提供的代码#include<stdio.h>#include<st......
  • C语言【面试】常用知识点总结之常用易错易混点解析
    第二部分:程序代码评价或者找错有符号整型和无符号整型混合运算时,有符号型自动转换成无符号型,运算的结果是无符号的。如果参与运算的数据类型不同,会自动转化为同一类再运算,这就是自动转换自动转换的规则如下:1.当参与运算的数据的类型不同时,编译系统会自动先将他们转换成......
  • 油管视频《编程思维》中的题目,使用C语言编写出来,第二集,反抗
    题目,假设要在人群中找一位领袖,领袖的相关信息有,他的眼睛是绿色的,如果他长着红头发,名字至少两个连续字母相同,如果戴眼镜的话,名字中有且仅有2个元音,否则名字中会有三个元音,只有一人附和以上条件,请下达指令涉及编程的基础原理1,结构体的使用,用于存储每个人的信息2,字符串的处理,......
  • C语言:指针1(详细讲解)
     目录指针变量和地址取地址操作符指针变量的大小指针变量类型意义指针解引⽤指针的+-整数const修饰指针const修饰变量const修饰指针变量指针的运算指针+-整数 指针的关系运算野指针指针未初始化 指针越界访问指针指向的空间被释放了避免野指针assert......
  • C语言---二维数组
    1.1概念        从逻辑上有行有列的数组,成为二维数组,相对来讲,只有行这种单一线性结构的数组称为一维数组。二维数组本质上是以数组作为数组元素的数组,即“数组的数组”。定义由行和列组成的二维表格形式元素,二维数组其实也就是矩阵基本格式。访问二维数组需要两个值......
  • 油管视频《编程思维》中的题目,使用C语言编写出来,第三集,炉膛机器人
    题目:假设起初只有一个机器人,他的炉膛里有一个数字0,和另一个未知的任意生成的编码,随着推移,原始机器人自我复制,制造出更多一样的炉膛机器人,被原始机器人自我复制制造出的每一个子机器人的熔炉内,都继承了原始机器人未知的编码,并且有一个属于自己,独一无二的编码刻在外壳,第二代炉膛......
  • 队列及其C语言实现
    2.3队列2.3.1什么是队列队尾入队,队头出队,一个受限制性的线性表。队列(Queue):具有一定操作约束的线性表•插入和删除操作:只能在一端插入,而在另一端删除。•数据插入:入队列(AddQ)•数据删除:出队列(DeleteQ)•先来先服务•先进先出:FIFO 2.3.2队列的抽象数据类型描述 ......
  • C语言面向对象风格编程解惑-全局变量性能分析
    C语言面向对象风格编程解惑-全局变量性能分析如果你是CPP老手,但在软件开发过程中要求采用C语言作为主要语言,首先遇到的是各种设计模式不方便应用了,感到非常困扰,然后就是认命之后走向另外一个极端,常常会有过度使用全局变量和goto语句的问题。CPP既然是CWithClass,自然不会排斥面......