avr-g++位域结构体初始化:多1值存RAM?如何强制立即数?
AVR-G++中位域结构体初始化的立即数/内存存储差异问题
我在Fedora 37上使用avr-g++ 10.2.0,目标平台为ATmega128,项目需要尽可能优化代码体积与RAM占用。
我通过位域结构体定义8位硬件寄存器端口:
struct MyPort { uint8_t someBit:1; uint8_t someOtherBit:1; uint8_t bit_1:1; uint8_t bit_2:1; uint8_t bit_3:1; uint8_t bit_4:1; uint8_t bit_5:1; uint8_t more_bit:1; };
并编写了constexpr初始化函数:
constexpr void Initialize(const MyPort & value) { port = value; }
其中port是硬件寄存器本身,我希望通过Initialize( {0,0,1,0,1,1,0,0} );的方式调用时,生成如下汇编:
ldi r24, 0x34 out 0x18, r24
但实际部分场景下,对应值会被存入初始化内存,生成的汇编为:
lds r24, 0x0280 out 0x18, r24
现象分析
我发现这个差异取决于初始化值的特征:
- 若8位值仅包含1个
1位(如0x80、0x10),则会被当作立即数处理; - 若包含多个
1位(如0xc0、0x11),则会被存入初始化内存。
举两个例子:
调用Initialize( {0,0,0,0,0,0,0,1} );生成的汇编:
ldi r24, 0x80 out 0x18, r24
调用Initialize( {0,0,0,1,0,0,0,1} );生成的汇编:
lds r24, 0x0280 out 0x18, r24
其中值0x88被存入了0x280地址的初始化内存段。我使用-Os编译参数,无法理解这种差异的原因,也希望避免不必要的内存占用。
简化复现示例
以下是简化后的测试代码:
struct MyPort { unsigned char b0:1; unsigned char b1:1; unsigned char b2:1; unsigned char b3:1; unsigned char b4:1; unsigned char b5:1; unsigned char b6:1; unsigned char b7:1; }; constexpr void Init(unsigned char addr, const MyPort & data) { *reinterpret_cast<MyPort *>(addr) = data; } int main(int argc, char ** argv) { Init( 0x34, {0,0,0,1,0,0,0,0} ); Init( 0x35, {0,0,0,1,0,0,1,0} ); return 0; }
编译命令:avr-g++ -Os test.cpp
反汇编结果(仅展示相关部分):
00000018 <main>: 18: 88 e0 ldi r24, 0x08 1a: 84 bb out 0x14, r24 1c: 80 91 60 00 lds r24, 0x0060 20: 85 bb out 0x15, r24 22: 90 e0 ldi r25, 0x00 24: 80 e0 ldi r24, 0x00 26: 08 95 ret
可见第一个寄存器用立即数初始化,第二个则将值存入内存(地址0x60),二者仅初始化值存在差异。除-O0外,所有优化级别下结果一致。
疑问
- 这种差异产生的原因是什么?
- 是否有方法强制使用立即数初始化,避免不必要的内存存储?
内容的提问来源于stack exchange,提问作者user2849906
相关产品推荐
相关产品推荐

