命名空间
变体
操作

位域

来自 cppreference.com
< c‎ | 语言

声明一个具有显式宽度(以位为单位)的成员。相邻的位域成员可以打包在一起以共享和跨越单个字节。

位域声明是 结构体联合体 成员声明,它使用以下 声明符

标识符 (可选) : 宽度
标识符 - 正在声明的位域的名称。名称是可选的:无名位域会引入指定数量的填充位。
宽度 - 一个整数 常量表达式,其值为大于或等于零且小于或等于底层类型的位数。当大于零时,这是该位域将占用的位数。值零仅允许用于无名位域,并且具有特殊含义:它指定类定义中的下一个位域将从分配单元的边界开始。

内容

[编辑] 解释

位域只能具有以下 三种(直到 C99)四种(自 C99 起)(直到 C23) 类型(可能具有 constvolatile 限定符)

  • unsigned int,用于无符号位域 (unsigned int b:3; 的范围为 0..7)
  • signed int,用于有符号位域 (signed int b:3; 的范围为 -4..3)
  • int,用于具有实现定义的符号性的位域(注意,这与关键字 int 在其他地方的含义不同,在其他地方它表示“有符号 int”。例如,int b:3; 的取值范围可能是 0..7-4..3
  • _Bool, 用于单比特位域 (bool x:1;) 的范围为 0..1,并且 隐式转换 遵循布尔转换规则。
(自 C99 起)
  • 位精确整数类型。(例如,_BitInt(5):4; 的范围为 -8..7,而 unsigned _BitInt(5):4; 的范围为 0..15)。
(自 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; // start 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 起) 一起使用。

[编辑] 注意事项

以下位域使用会导致未定义的行为

位域的以下属性是未指定的

  • 保存位域的分配单元的对齐方式

位域的以下属性是由实现定义的

  • 类型为 int 的位域是作为有符号还是无符号处理
  • intsigned intunsigned 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++ 文档 中的 位域