use*_*116 6 c optimization union gcc struct
考虑以下代码:
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};
}
Run Code Online (Sandbox Code Playgroud)
当使用位字段在嵌入式应用程序中打孔寄存器时,这种通用模式会出现很多。使用ARM最近gcc编译器(如GCC 8.2或7.3 GCC)与-O3和-std=c11,我得到以下组件:
sub sp, sp, #8
movs r3, #7
str r3, [sp, #4]
add sp, sp, #8
bx lr
Run Code Online (Sandbox Code Playgroud)
这几乎正是您想要和期望的。变量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};
}
Run Code Online (Sandbox Code Playgroud)
不幸的是,生成的程序集并没有如此优化:
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
Run Code Online (Sandbox Code Playgroud)
对于密集封装的寄存器,每个位的读-修改-写操作可能会变得...昂贵。
阻止gcc优化初始化(例如纯结构)的联合/匿名结构有什么特别之处?
小智 1
我希望我能回答你的问题。问题是 GCC 编译器有一些关于 C 到汇编的转换的预定义规则,当您进行一个union和struct一个的转换时uint32_t,它没有预定义的模式,这就是为什么生成的程序集没有像第一个示例那样优化的原因。
我建议你使用cast来解决这个问题。
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};
volatile uint32_t rawA = *((uint32_t *) &foo);
volatile uint32_t rawB = *((uint32_t *) &foo + sizeof(uint32_t);
}
Run Code Online (Sandbox Code Playgroud)