位域
来自 cppreference.cn
声明一个具有显式宽度(以位为单位)的成员。相邻的位域成员可以打包以共享和跨越各个字节。
标识符(可选) : 宽度 |
|||||||||
标识符 | - | 要声明的位域的名称。名称是可选的:无名位域引入指定数量的填充位 |
宽度 | - | 一个整数常量表达式,其值大于或等于零,且小于或等于底层类型中的位数。当大于零时,这是此位域将占用的位数。值零仅允许用于无名位域,并且具有特殊含义:它指定类定义中的下一个位域将从分配单元的边界开始。 |
目录 |
[编辑] 解释
位域只能具有以下类型之一(可能带有 const 或 volatile 限定符)
- unsigned int,用于无符号位域(例如,unsigned int b : 3; 的范围为
[
0,
7]
) - signed int,用于有符号位域(signed int b : 3; 的范围为
[
-4,
3]
) - int,用于具有实现定义的符号性的位域(请注意,这与关键字 int 在其他任何地方的含义不同,在其他任何地方它都表示“signed int”)。例如,int b : 3; 可能具有值范围
[
0,
7]
或[
-4,
3]
。
|
(自 C99 起) |
|
(自 C23 起) |
其他实现定义的类型可能是可接受的。位域是否可以具有原子类型也是实现定义的。(自 C11 起) 位域中的位数(宽度)设置了它可以容纳的值范围的限制
运行此代码
#include <stdio.h> struct S { // three-bit unsigned field, // allowed values are 0...7 unsigned int b : 3; }; int main(void) { struct S s = {7}; ++s.b; // unsigned overflow printf("%d\n", s.b); // output: 0 }
允许多个相邻的位域打包在一起(通常也是如此)
运行此代码
#include <stdio.h> struct S { // will usually occupy 4 bytes: // 5 bits: value of b1 // 11 bits: unused // 6 bits: value of b2 // 2 bits: value of b3 // 8 bits: unused unsigned b1 : 5, : 11, b2 : 6, b3 : 2; }; int main(void) { printf("%zu\n", sizeof(struct S)); // usually prints 4 }
宽度为零的特殊无名位域会中断填充:它指定下一个位域从下一个分配单元的开头开始
运行此代码
#include <stdio.h> struct S { // will usually occupy 8 bytes: // 5 bits: value of b1 // 27 bits: unused // 6 bits: value of b2 // 15 bits: value of b3 // 11 bits: unused unsigned b1 : 5; unsigned : 0; // starts a new unsigned int unsigned b2 : 6; unsigned b3 : 15; }; int main(void) { printf("%zu\n", sizeof(struct S)); // usually prints 8 }
由于位域不一定从字节的开头开始,因此无法获取位域的地址。指向位域的指针是不可能的。位域不能与 sizeof
和 _Alignas
(自 C11 起)(直到 C23)alignas
(自 C23 起)(自 C11 起) 一起使用。
[编辑] 注解
以下位域的用法会导致未定义行为
- 在位域上调用 offsetof。
以下位域的属性是未指定的
- 保存位域的分配单元的对齐方式。
以下位域的属性是实现定义的
- 类型为 int 的位域是否被视为有符号或无符号。
- 是否允许使用 int、signed int、unsigned int、_Bool(自 C99 起)和(可能unsigned)_BitInt(N)(自 C23 起) 以外的类型。
|
(自 C11 起) |
- 位域是否可以跨越分配单元边界。
- 分配单元内位域的顺序(在某些平台上,位域从左到右打包,而在另一些平台上,位域从右到左打包)。
即使 _Bool 的对象表示形式中的位数至少为 CHAR_BIT,类型为 _Bool 的位域的宽度也不能大于 1。 |
(自 C99 起) |
在 C++ 编程语言中,位域的宽度可以超过底层类型的宽度(但额外的位是填充位),并且类型为 int 的位域始终是有符号的。
[编辑] 引用
- C23 标准 (ISO/IEC 9899:2024)
- 6.7.2.1 结构体和联合体说明符
- C17 标准 (ISO/IEC 9899:2018)
- 6.7.2.1 结构体和联合体说明符
- C11 标准 (ISO/IEC 9899:2011)
- 6.7.2.1 结构体和联合体说明符
- C99 标准 (ISO/IEC 9899:1999)
- 6.7.2.1 结构体和联合体说明符
- C89/C90 标准 (ISO/IEC 9899:1990)
- 3.5.2.1 结构体和联合体说明符
[编辑] 参见
C++ 文档 关于 位域
|