用宏定义的结构体是【全局变量】
全局变量的【初始化值】存在 FLASH 里
但是 -Oz 最小体积优化下,编译器把 "全 0 初始化" 给优化删除了!
所以变量拿到的还是 RAM 上电脏值!**
1. 先看你这句宏
cpp
#define LIB_RingBuffer_EXPORT(x,type,num) \
type x##Buffer[num]; \
RingBufferPARM x = { \
x##Buffer, \
num, \
sizeof(type), \
0, \
0, \
0, \
0, \
};
调用:
cpp
LIB_RingBuffer_EXPORT(gUart2_RX_RingBuffer, uint8_t, 64);
展开后 = 全局结构体变量:
cpp
uint8_t gUart2_RX_RingBufferBuffer[64];
RingBufferPARM gUart2_RX_RingBuffer = {
gUart2_RX_RingBufferBuffer,
64,
1,
0,
0,
0,
0,
};
2. 重点来了:编译器 -Oz 做了什么?
** 编译器规则:全局变量如果是【0 + 常量指针】组合
编译器会判定它属于【.bss 段】(需要自动清 0 的段)
但是!
你的结构体里有:指针 + 数字,编译器识别混乱
-Oz 为了减体积,直接【不执行 Flash → RAM 的初始化赋值】!
结果:
cpp
msgBuff = 正常(指针被保留)
maxMsgNum = 正常
msgSize = 正常
deIndex = 随机脏值 ❌
enIndex = 随机脏值 ❌
deNum = 随机脏值 ❌
enNum = 随机脏值 ❌
你写的 {0,0,0,0} 被编译器优化吃了!
3. 为什么 LIB_RingBuffer_Clear() 就一定有效?
因为:
cpp
void LIB_RingBuffer_Clear(PRingBufferPARM p)
{
p->deIndex = 0;
p->enIndex = 0;
p->deNum = 0;
p->enNum = 0;
}
这是运行时指令 !不是初始化,是运行时赋值! 优化器绝对不敢删!
所以:
- 初始化宏 = 可能被优化
- 运行时赋值 = 100% 生效
你写的:
RingBufferPARM x = {0,0,0,0};
编译器 -Oz 心里想:
"反正都是 0,我不占 Flash 了,省点空间,让它走.bss 吧"
结果:
没给你赋值成功 → 变量还是脏值!
你手动 Clear():
"我就要在运行时赋值 0,你别管为什么" 编译器老老实实执行 → 正常!
✅ 最终结论(100% 正确)
全局结构体的 {0} 初始化,在 -Oz 优化下不可靠!
必须在【运行时】手动调用一次 Clear () 清零!
这就是为什么:
- 下载运行正常(调试器会强制清 RAM)
- 断电重启异常(编译器没给你赋值)
- 手动 Clear 就 100% 正常
一句话收尾:
不是你写错了,是编译器 -Oz 为了省空间,把你的全局变量初始化 "偷" 了! 运行时手动清零 = 100% 可靠,永远解决