C 位域

除了结构或联合的成员的声明符外,结构声明符也可以是指定数目的位,称为“位域”。其长度从字段名称的声明符到冒号。 位域被解释为整型类型。

语法

struct-declarator:
declarator
type-specifierdeclaratoropt:constant-expression

constant-expression 指定域的宽度(以位为单位)。 declaratortype-specifier 必须为 unsigned intsigned intint,而且 constant-expression 必须为非负整数值。 如果值为零,则声明没有任何 declarator。 不允许位域的数组、指向位域的指针和返回位域的函数。 可选的 declarator 命名位域。 位域只能声明为结构的一部分。 address-of 运算符 (&) 不能应用于位域组件。

未命名位域不可引用,且其内容在运行时是不可预测的。 它们可以出于对齐目的用作“虚拟”字段。 宽度指定为 0 的未命名位域确保在 struct-declaration-list 中跟在其后的成员的存储在 int 边界开始。

位字段中的位数必须小于或等于基础类型的大小。 例如,以下两个语句均不合法:

short a:17;        /* Illegal! */
int long y:33;     /* Illegal! */

以下示例定义了一个名为 screen 的二维结构数组。

struct
{
    unsigned short icon : 8;
    unsigned short color : 4;
    unsigned short underline : 1;
    unsigned short blink : 1;
} screen[25][80];

该数组包含 2,000 个元素。 每个元素都是包含以下四个位域成员的单个结构:iconcolorunderlineblink。 每个结构的大小是 2 个字节。

位域与整数类型具有相同的语义。 位域在表达式中的使用方式与同样基类型使用变量的方式完全相同。 位域中有多少位并不重要。

Microsoft 专用

定义为 int 的位域被视为 signed。 ANSI C 标准的 Microsoft 扩展允许对位域使用 charlong 类型(signedunsigned)。 带基类型 longshortcharsignedunsigned)的未命名位域强制与适合基类型的边界对齐。

在整数中按照从最高有效位到最低有效位的顺序来分配位域。 在以下代码中

struct mybitfields
{
    unsigned short a : 4;
    unsigned short b : 5;
    unsigned short c : 7;
} test;

int main( void )
{
    test.a = 2;
    test.b = 31;
    test.c = 0;
    return 0;
}

test 的位将按如下所示排列:

00000001 11110010
cccccccb bbbbaaaa

由于 8086 系列处理器将整数值的低字节存储在高字节之前,因此整数 0x01F2 将按 0xF2 后跟 0x01 的形式存储在物理内存中。

ISO C99 标准允许实现选择位域是否可以跨两个存储实例。 请考虑这种结构,其中存储了共计 64 位的位域:

struct
{
    unsigned int first : 9;
    unsigned int second : 7;
    unsigned int may_straddle : 30;
    unsigned int last : 18;
} tricky_bits;

标准 C 实现可以将这些位域打包成两个 32 位整数。 它可以将 tricky_bits.may_straddle 作为 16 位存储在一个 32 位整数中,作为 14 位存储在下一个 32 整数中。 Windows ABI 约定将位域打包成单个存储整数,不跨存储单元。 Microsoft 编译器将存储上述示例中的每个位域,使它完全适应单个 32 位整数。 在这种情况下,firstsecond 存储在一个整数中,may_straddle 存储在另一个整数中,last 存储在第三个整数中。 如果是一个 tricky_bits 实例,sizeof 运算符则返回 12。 有关详细信息,请参阅结构成员的填充和对齐

结束 Microsoft 专用

请参阅

结构声明