命名空间
变体
操作

位域

来自 cppreference.cn
< c‎ | language

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

位域声明是一个 structunion 成员声明,它使用以下声明符

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

目录

[编辑] 解释

位域只能具有以下类型之一(可能带有 constvolatile 限定符)

  • unsigned int,用于无符号位域(例如 unsigned int b : 3; 的范围是 [07]
  • signed int,用于有符号位域(signed int b : 3; 的范围是 [-43]
  • int,用于具有实现定义有符号性的位域(请注意,这与关键字 int 在其他任何地方的含义不同,其他地方表示“signed int”)。例如,int b : 3; 的值范围可能是 [07][-43]
  • _Bool,用于单比特位域(例如 bool x : 1;)的范围是 [01],并且其隐式转换遵循布尔转换规则。
(C99 起)
  • 位精确整数类型(例如 _BitInt(5) : 4; 的范围是 [-87],而 unsigned _BitInt(5) : 4; 的范围是 [015])。
(自 C23 起)

其他实现定义的类型可能被接受。位域是否可以具有原子类型也是实现定义的。(C11 起) 位域中的位数(width)设定了它可以容纳的值的范围限制

#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 起) 一起使用。

[编辑] 注意

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

位域的以下属性未指定

  • 包含位域的分配单元的对齐方式。

位域的以下属性实现定义

  • 类型为 int 的位域是被视为有符号还是无符号。
  • 是否允许除了 intsigned intunsigned int_Bool(C99 起),以及(可能为 unsigned_BitInt(N)(C23 起) 之外的类型。
  • 是否允许原子类型。
(C11 起)
  • 位域是否可以跨越分配单元边界。
  • 位域在分配单元内的顺序(在某些平台上,位域从左到右打包,在其他平台上从右到左)。

尽管 _Bool 的对象表示中的位数至少为 CHAR_BIT,但类型为 _Bool 的位域的 width 不能大于 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++ 文档 关于 位域