编译器优化诱发的BUG
编译器优化诱发的 BUG
有如下枚举类型:
1 | typedef enum |
如果在枚举末尾不添加一个类似 AAAA = 0X1111 这样需要占用 short 类型(即 16 位)的成员,编译器可能会将这个枚举类型优化为 char 类型(8 位)。
但开发者原本的意图显然是 short 类型——因为初始化值写的是 0X0001,而不是 0X01。一旦编译器将其优化为 char,后续再按照 short 类型去使用,就会产生难以察觉的 BUG。
如何解决?
很简单:在枚举末尾添加一个高 8 位不为 0 的值即可,例如 AAAA = 0X1111。
有了这个成员,编译器就不会再将枚举类型优化为 char,而是保留为 short。
会引发什么样的 BUG?
例 1:跨枚举类型传参导致数据截断
1 | typedef enum |
假设有一个函数,其形参类型为 TEST_ENUM1,函数内部用一个 short 类型变量接收该参数。起初,传入的参数都来自 TEST_ENUM1,一切正常。
但当你认为 TEST_ENUM1 与 TEST_ENUM2 本质上相同,于是将 TEST_ENUM2 中的枚举值作为实参传入该函数时,BUG 就出现了:
TEST_ENUM2 的枚举值会被强制截断为 char 类型,只保留低 8 位,高 8 位数据被丢弃。
如果这个值要通过通信发送给从设备,而设备期望完整的 16 位数据,那么通信就会失败,得不到预期的结果。
例 2:结构体大小与预期不符
1 | typedef enum |
使用 sizeof 关键字(注意:sizeof 是关键字,也是单目运算符,但并非函数)获取 TEST_STRUCT 的大小时,得到的结果很可能与你手动计算的不一致。
如果你确定自己的计算没有错误,那么大概率就是因为编译器悄悄优化了枚举的大小,导致结构体的内存布局发生了变化。
总结:当枚举中所有成员的值都能用
char表示时,编译器为了节省空间,可能会将其底层类型优化为char。如果业务逻辑依赖枚举为 16 位或更大,记得在枚举末尾显式添加一个“大数”成员,强制编译器保持其大小。这类隐式优化极易引发隐蔽的跨模块、跨数据类型的 BUG,务必警惕。
