考虑以下代码:
typedef struct {
uint32_t a : 1;
uint32_t b : 1;
uint32_t c : 30;
} Foo1;
void Fun1(void) {
volatile Foo1 foo = (Foo1) {.a = 1, .b = 1, .c = 1};
}
在嵌入式应用程序中使用位字段对寄存器进行打孔时,此常规模式会出现很多。使用带有-O3
和-std=c11
的最新ARM gcc编译器(例如gcc 8.2或gcc 7.3),我得到以下程序集:
sub sp, sp, #8
movs r3, #7
str r3, [sp, #4]
add sp, sp, #8
bx lr
这几乎就是您想要和期望的。 Foo
不是易失性的,因此在将最终存储到易失性变量(寄存器)0x7
之前,可以将每个位的初始化组合在一起,成为文字foo
。
但是,能够操纵整个寄存器的原始内容很方便,这会导致位字段的匿名实现:
typedef union {
struct {
uint32_t a : 1;
uint32_t b : 1;
uint32_t c : 30;
};
uint32_t raw;
} Foo2;
void Fun2(void) {
volatile Foo2 foo = (Foo2) {.a = 1, .b = 1, .c = 1};
}
不幸的是,生成的程序集并未如此优化:
sub sp, sp, #8
ldr r3, [sp, #4]
orr r3, r3, #1
str r3, [sp, #4]
ldr r3, [sp, #4]
orr r3, r3, #2
str r3, [sp, #4]
ldr r3, [sp, #4]
and r3, r3, #7
orr r3, r3, #4
str r3, [sp, #4]
add sp, sp, #8
bx lr
对于密集封装的寄存器,每位的读-修改-写操作可能会变得...昂贵。
union /匿名结构有什么特别之处,它阻止了gcc像纯结构一样优化初始化?