位字段是唯一打包在字节中的对象。也就是说,两个位字段可存储在同一字节中。位字段的大小可以从 1 位到 32 位不等,但它们从不跨越 4 字节边界。
对于大端模式,位字段按定义的顺序从最高有效位 (MSB) 到最低有效位 (LSB) 打包到寄存器中。位字段按从最高有效字节 (MSbyte) 到最低有效字节 (LSbyte) 的顺序打包到内存中。对于小端模式,位字段按照定义的顺序从 LSB 到 MSB 打包到寄存器中,并按照从 LSbyte 到 MSbyte 的顺序打包到内存中。
以下是有关如何处理位字段的一些详细信息:
- 纯文本 int 位字段是无符号的。考虑以下 C 代码:
struct st
{
int a:5;
} S;
foo()
{
if (S.a < 0)
bar();
}
在此示例中, bar()永远不会被调用,因为位字段“a”是无符号的。如果需要有符号位字段,请使用 signed int。
- 支持 long long 类型的位字段。
- 位字段被视为声明的类型。
- 包含位字段的结构的大小和对齐方式取决于位字段的声明类型。例如,考虑以下结构:
struct st {int a:4};
此结构使用了 4 个字节并在 4 个字节处对齐。
- 未命名的位字段会影响结构或联合体的对齐方式。例如,考虑以下结构:
struct st{char a:4; int :22;};
此结构使用了 4 个字节并在 4 字节边界处对齐。
- 根据位字段的声明类型访问声明为易失性的位字段。易失性位字段引用只生成一个对其存储的引用;多个易失性位字段访问不会被合并。
图 6-4 使用以下位字段定义说明位字段打包:
struct{
int A:7
int B:10
int C:3
int D:2
int E:9
}x;
A0 表示字段 A 的最低有效位;A1 表示下一个最低有效位,以此类推。同样,位字段在内存中的存储是通过逐字传输而不是逐位传输完成的。
A | A | A | A | A | A | A | B | B | B | B | B | B | B | B | B | B | C | C | C | D | D | E | E | E | E | E | E | E | E | E | X |
6 | 5 | 4 | 3 | 2 | 1 | 0 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 2 | 1 | 0 | 1 | 0 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | X |
A | A | A | A | A | A | A | B | B | B | B | B | B | B | B | B | B | C | C | C | D | D | E | E | E | E | E | E | E | E | E | X |
6 | 5 | 4 | 3 | 2 | 1 | 0 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 2 | 1 | 0 | 1 | 0 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | X |
X | E | E | E | E | E | E | E | E | E | D | D | C | C | C | B | B | B | B | B | B | B | B | B | B | A | A | A | A | A | A | A |
X | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 1 | 0 | 2 | 1 | 0 | 9 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
B | A | A | A | A | A | A | A | B | B | B | B | B | B | B | B | E | E | D | D | C | C | C | B | X | E | E | E | E | E | E | E |
0 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 1 | 0 | 1 | 0 | 2 | 1 | 0 | 9 | X | 8 | 7 | 6 | 5 | 4 | 3 | 2 |
图例:X = 未使用,MS = 最高有效,LS = 最低有效 |