通过读取周围的可寻址存储器单元(字节或字),屏蔽和移位来实现位字段.
更确切地说,读取位字段被实现为读取移位掩码,并且写入位字段被实现为读取 - 掩码移位值以进行写入或写入.
这是相当昂贵的,但如果您打算紧凑地存储数据并愿意为按位操作付出代价,那么位字段在源级别提供更清晰,更轻的语法,用于您可以手动编写的相同操作.你失去的是对布局的控制(标准没有规定如何从包含的字中分配位字段,这将因编译器与编译器的不同而不同于按位操作的含义).
每当您怀疑C编译器对给定构造的作用时,您总是可以读取汇编代码:
struct s {
unsigned int a:3;
unsigned int b:3;
} s;
void f(void)
{
s.b = 5;
}
int g(void)
{
return s.a;
}
Run Code Online (Sandbox Code Playgroud)
这是通过以下方式编译的gcc -O -S:
_f: ## @f
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
movq _s@GOTPCREL(%rip), %rax
movb (%rax), %cl ; read
andb $-57, %cl ; mask
orb $40, %cl ; since the value to write was a constant, 5, the compiler has pre-shifted it by 3, giving 40
movb %cl, (%rax) ; write
popq %rbp
retq
.cfi_endproc
.globl _g
.align 4, 0x90
_g: ## @g
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp7:
.cfi_def_cfa_offset 16
Ltmp8:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp9:
.cfi_def_cfa_register %rbp
movq _s@GOTPCREL(%rip), %rax
movzbl (%rax), %eax
andl $7, %eax
popq %rbp
retq
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)