请考虑以下代码:
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};
}
在嵌入式应用程序中使用位字段来穿孔寄存器时,经常会出现这种通用模式。使用最近的ARM gcc编译器(例如gcc 8.2或gcc 7.3),通过-O3
和-std=c11
,我得到了下面的程序集:
sub sp, sp, #8
movs r3, #7
str r3, [sp, #4]
add sp, sp, #8
bx lr
这几乎正是您想要和期望的; Foo
不是易失性的,因此在最终存储到易失性变量(寄存器)foo
之前,可以将每个位的初始化一起组合到文字0x7
中。
然而,能够操作整个寄存器的原始内容是很方便的,这会产生位字段的匿名实现:
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 / anonymous结构体有什么特殊之处,它阻止gcc像pure结构体一样优化初始化?
1条答案
按热度按时间zysjyyx41#
我希望我能回答你的问题。问题是GCC编译器有一些关于C到汇编程序转换的预定义规则,当你用一个
struct
和一个uint32_t
创建一个union
时,它没有预定义的模式,这就是为什么最终的汇编程序没有像第一个例子那样优化。我建议你用铸造来解决这个问题。