专业做辅助的网站,seo sem优化,莱西做网站公司,创意网站案例#x1f984;个人主页:小米里的大麦-CSDN博客 #x1f38f;所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html #x1f381;代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com ⚙️操作环境:Visual Studio 2022 目录
一、什么是位段#xff1f;
二、… 个人主页:小米里的大麦-CSDN博客 所属专栏:https://blog.csdn.net/huangcancan666/category_12718530.html 代码托管:黄灿灿 (huang-cancan-xbc) - Gitee.com ⚙️操作环境:Visual Studio 2022 目录
一、什么是位段
二、位段的内存分配
三、位段的跨平台问题
四、位段的应用
五、代码示例
六、位段的限制
七、位段与位域的区别
八、总结
共勉 一、什么是位段 位段Bit field是一种数据结构它允许你在单个整数变量中分配特定数量的位给不同的字段。这样做的目的是为了节省内存空间。 位段Bit field的基本单位不是字节而是位bit。位段是在单个整数类型变量中按照位来分配存储空间的一种数据结构。位段的声明和结构是类似的有两个不同 位段的成员必须是 int、unsigned int 或signed int 。 位段的成员名后边有一个冒号和一个数字。 一个位段由多个成员组成每个成员都有自己的名称和宽度即占用的位数。例如
举个例子假设你需要存储三个设置选项每个选项只需要一两位来表示开启或关闭的状态。
如果用普通的整数变量来存储这些选项每个整数至少会占用32位如果是32位系统的话。
但如果使用位段你就可以只用三位来表示这三个选项大大节省了空间。struct Settings {unsigned int option1 : 1; // 占用1位unsigned int option2 : 1; // 占用1位unsigned int option3 : 1; // 占用1位
};
二、位段的内存分配 位段的成员可以是 int unsigned int signed int 或者是 char 属于整形家族类型 位段的空间上是按照需要以4个字节 int 或者1个字节 char 的方式来开辟的。 位段涉及很多不确定因素位段是不跨平台的注重可移植的程序应该避免使用位段。 Settings 就是一个位段类型, 那位段 Settings 的大小是多少一起来看看 请注意 虽然位段是以位为单位但实际存储这些位段的变量的大小通常是以字节为单位的。这是因为计算机内存是以字节为基本单元进行寻址的。例如即使你的位段结构体只占用了8位即1字节由于内存对齐的要求实际的结构体大小可能仍然是4字节。 总结一下 位段的基本单位位bit位段存储的单位字节byte但位段本身按位分配空间实际结构体的大小通常以字节为单位取决于编译器的内存对齐策略。 再看看这个 #include stdio.h
struct A
{char _a : 3;char _b : 4;char _c : 5;char _d : 4;
};
int main()
{struct A a {0};a._a 10;a._b 12;a._c 3;a._d 4;return 0;
}假设位段分配的内存中的比特位是从右向左使用的分配剩余的bit位不够使用时浪费掉剩余内存。则 执行程序a._a 10; 10的二进制为1010放入_a中由于_a只有3bit需要截断所以舍弃最高位1放入010 执行程序a._b 12;,12的二进制为1100刚好可以放入如下图 执行程序a._c 3;3的二进制为11由于_c有5bit高位添0放入00011如下图 执行程序a._d 4;4的二进制为100,放入0100如下图 程序就基本执行完了那么内存中是什么样的呢根据上面分析我们一开始给结构体初始化为0我们可以得到 也就是 由于机器是小端存储所以内存上应该是62 03 04. 经过调试可以看到 所以位段的大小计算主要取决于你如何定义它以及编译器的具体实现。 struct BitField {unsigned int a: 3; // 占用3位unsigned int b: 5; // 占用5位unsigned int c: 1; // 占用1位
};
这里a占用了3位b占用了5位而c占用了1位。
理论上这些位可以紧密排列在一起但是实际的内存对齐规则可能会导致额外的空间被分配。a、b和c总共占用了9位。
如果使用32位的整数类型则最终的位段结构可能会占用完整的32位尽管实际上只使用了9位。所以你可以使用sizeof运算符来确定位段的实际大小
#include stdio.hint main() {struct BitField bitField;printf(Size of BitField: %zu bytes\n, sizeof(bitField));return 0;
} 要计算位段的实际大小你需要考虑以下几点 位的总和计算所有成员位数之和。字边界对齐大多数编译器会按照字边界对齐原则来存储数据这意味着即使位数总和小于一个字的基本单位通常是8位或更常见的是32位也会向上取整到下一个字的大小。编译器特定行为不同的编译器可能有不同的实现细节包括如何处理跨越字边界的位字段。 三、位段的跨平台问题 跟结构相比位段可以达到同样的效果但是可以很好的节省空间但是有跨平台的问题存在。简略一点看 int 位段被当成有符号数还是无符号数是不确定的。 位段中最大位的数目不能确定。16位机器最大1632位机器最大32写成27在16位机器会出问题。 位段中的成员在内存中从左向右分配还是从右向左分配标准尚未定义。 当一个结构包含两个位段第二个位段成员比较大无法容纳于第一个位段剩余的位时是舍弃剩余的位还是利用这是不确定的 详细的看 位字段的顺序在某些平台上位字段的顺序可能会影响其布局。例如在一些系统中位字段是从低到高排列的从右到左而在其他系统中则可能是从高到低排列的从左到右。 位字段的对齐编译器可能会根据目标平台的内存对齐要求来对位字段进行对齐这意味着位字段的实际布局可能会与预期不同。例如在某些架构上整数类型可能需要在特定的地址对齐如4字节边界这可能导致额外的空间被插入到位字段之间或之后。 位字段的大小不同的编译器可能会有不同的默认整数类型大小。例如int 类型在某些系统上可能是32位在另一些系统上可能是64位。这会影响位字段的最大容量和布局。 位字段的填充为了满足内存对齐的要求编译器可能会在位字段之间添加填充位。例如如果一个位字段在32位边界结束而下一个位字段需要从新的32位边界开始则编译器可能会在它们之间插入未使用的位。 位字段的访问位字段的读写操作在不同的编译器和平台上可能会有所不同。有些编译器提供特定的操作符来访问位字段而其他编译器可能需要使用位操作如位移和按位与操作来访问位字段。 为了避免位字段的跨平台问题你可以采取以下措施 明确指定整数类型使用 stdint.h 中定义的固定宽度整数类型如 uint8_t, uint16_t, uint32_t 等以确保位字段的大小在所有平台上都是一致的。手动管理对齐如果需要严格的对齐控制可以考虑手动在结构体中添加填充字段。避免依赖于位字段的特定布局如果程序逻辑依赖于位字段的具体布局那么在不同的平台上测试并验证行为是很重要的。使用位操作使用位操作如位移、按位与等来访问位字段这样可以确保代码在不同平台上的一致性。 四、位段的应用
位段Bit field在计算机科学和软件工程中有多种应用特别是在需要高效存储和访问数据的情况下。通常用于处理那些只需要少量位的数据比如状态标志、计数器等。通过使用位段我们可以更有效地利用内存资源。 此外位段还可以用来模拟位数组。例如如果我们想要表示一个有 8 个元素的布尔数组可以使用一个字节来存储这个数组的所有元素
struct {bool arr[8] : 1; // 每个元素占用1位
} bit_array;
这样我们就用一个字节的空间实现了布尔数组的功能。
五、代码示例
下面是一些使用位段的例子
// 示例1定义一个表示颜色的位段
struct color {unsigned char red : 5; // 红色部分占用5位unsigned char green : 6; // 绿色部分占用6位unsigned char blue : 5; // 蓝色部分占用5位
};// 示例2定义一个表示时间的位段
struct time {unsigned short hour : 5; // 小时部分占用5位unsigned short minute : 6; // 分钟部分占用6位unsigned short second : 5; // 秒钟部分占用5位
};
当我们声明一个位段结构体变量时我们可以同时初始化所有成员的值。例如
struct color my_color { .red 0x1f, .green 0x3f, .blue 0x1f }; // 初始化颜色位段变量
struct time my_time { .hour 12, .minute 30, .second 0 }; // 初始化时间位段变量
六、位段的限制
虽然位段可以节省内存空间但它也有一些限制
位段不能包含浮点数成员。位段不能包含字符串成员。位段不能包含结构体成员。位段不能包含联合体成员。
七、位段与位域的区别
位段和位域都是用来表示二进制位的结构体类型但它们有一些区别
位段可以包含多个成员而位域只有一个成员。位段的成员可以有不同的宽度而位域的成员必须具有相同的宽度。位段的成员可以跨越字边界而位域的成员不能跨越字边界。
八、总结
位段是 C 语言提供的一种非常有用的工具可以帮助我们更高效地管理内存。但是由于其跨平台性的问题我们在使用位段时也需要谨慎考虑。
共勉