初始化结构与匿名结构有什么区别?

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 到汇编的转换的预定义规则,当您进行一个unionstruct一个的转换时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)