平台:STM32F103RCT6+MDK
笔者在调试时发现,结构体不同类型成员的定义顺序对于程序运行过程中的取值可能会产生很大的BUG
开始时定义:
/***********************输入参数结构体**********************/
typedef struct {
u8 TempRange; //温度最大值 ℃
float PressRange; //压力范围 Kpa
u8 HandTemp; //手工温度 ℃
float HandPress; //手工压力 Kpa
HORA HandOrAutoTemp; //手工or自动温度 此处数据类型为枚举类型
HORA HandOrAutoPress; //手工or自动压力 此处数据类型为枚举类型
}INPUTSTRUCT;
INPUTSTRUCT InputPara={ /*输入界面数据*/
100, //温度范围 -50~?
101.32f, //压力范围
0, //手工温度值
0.0f, //手工压力值
Manual, //手工/自动? 手工
Manual //手工/自动? 手工
};
在以上的定义中,编译无警告无错误,程序正常运行,但是在整个程序里面调用的所有float类型数据都不会是定义时候的值!即使有的float数据不是在本结构体变量中定义的,调用的值也会异常!而其他的不管是字符型,整型或者枚举类型都不会有错误
经过漫长的DEBUG,终于定位问题所在:
将
float PressRange; //压力范围 Kpa
u8 HandTemp; //手工温度 ℃
交换位置
结构体定义和变量定义修改为:
/***********************输入参数结构体**********************/
typedef struct {
u8 TempRange; //温度最大值 ℃
u8 HandTemp; //手工温度 ℃
float PressRange; //压力范围 Kpa
float HandPress; //手工压力 Kpa
HORA HandOrAutoTemp; //手工or自动温度
HORA HandOrAutoPress; //手工or自动压力
}INPUTSTRUCT;
INPUTSTRUCT InputPara={ /*输入界面数据*/
100, //温度范围 -50~?
0, //手工温度值
101.32f, //压力范围
0.0f, //手工压力值
Manual, //手工/自动? 手工
Manual //手工/自动? 手工
};
编译下载,程序运行正常,所有的float变量也恢复正常!
奇怪的是,在另一个结构体定义中,float的顺序并没有对整个程序造成影响:
DEBUGSTRUCT DebugPara={ /*调试界面数据*/
50.0f, //流量系数
9.8f, //重力加速度
0.27f, //风阻系数
5.0f, //节流件宽度
10.0f, //总质量
200.0f, //等效力臂
200.0f, //节流件长度
10.0f, //保留长度
0, //手工零点
Relative, //相对/绝对? 相对零点
Baud9600, //波特率
0x00, //模块地址
0, //静态置零
50.0f, //K0范围
0, //K1范围
... ...
};
对于float变量,内存中的储存方式是以指数方式存储的,这是浮点数与其他类型数据在内存上的存储区别。所以笔者猜测,在定义结构体时,由于偶尔的一次排序差别导致float数据在内存上偏移了n个字节,MCU在取值时每次都取了错误的float数据,导致取值与原本的值有很大差别。
而有时候在定义成员时,由于成员之间的排列顺序正好弥补了本该产生的字节对不齐(如笔者举的第二个例子)所以会“负负得正”正好没有出现问题。
由于该问题没有一个确切的产生时机,所以在每次出现这种bug时无法精确定位到关键所在,目前的办法是,定义变量时不对变量赋初值,定义好变量之后再对各个成员进行赋初值,这样不会产生bug:
INPUTSTRUCT InputPara;
int main(void)
{
InputPara.TempRange=100; //温度最大值 ℃
InputPara.PressRange=101.32f; //压力范围 Kpa
InputPara.HandTemp=0; //手工温度 ℃
InputPara.HandPress=0.0f; //手工压力 Kpa
InputPara.HandOrAutoTemp=Manual; //手工or自动温度
InputPara.HandOrAutoPress=Manual; //手工or自动压力
... ...
}
以上这种办法就可以不考虑结构体成员的排序问题,也不会产生错误。