变量定义的顺序不同,MDK的优化结果却不一样

2019-07-14 14:49发布


问题描述:
使用MDK4或5编译ST的USB-host库时,里面有个USB_OTG_BSP_uDelay函数,本函数本身在-03级优化下是没有问题的,但我手痒,对里面的变量的定义顺序做了一下修改,结果-o3优化下出问题了(表现为该延时函数不准确,导致部分U盘枚举失败),请教大师分析一下:
错误改法: 将定义 “const Uint32 utime = (Uint32)120 * usec / 7;” 放到 “__IO Uint32 uCount = 0;” 代码前面。
我的问题:仅仅是变量定义的顺序不同,为什么优化后结果却不一样(不是存储对齐的问题)?


正常的代码如下:
void USB_OTG_BSP_uDelay(const uint32_t usec)
{
__IO Uint32 uCount = 0;
const Uint32 uTime = (Uint32)120 * usec / 7;

while (1)
{
   if (++uCount > uTime)
   {
    return;
   }
}
}

错误的代码如下:
void USB_OTG_BSP_uDelay(const uint32_t usec)
{
const Uint32 uTime = (Uint32)120 * usec / 7;
__IO Uint32 uCount = 0;


while (1)
{
   if (++uCount > uTime)
   {
    return;
   }
}
}


附件是正常的与错误的反汇编截图,请大家指点!





友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
15条回答
7762642422d
2019-07-16 06:42
本帖最后由 moyanming2013 于 2017-5-12 14:09 编辑

1.首先,强烈建议按如下规则执行定义和赋值(越是新的编译器越是会消弱这种规则,比如MDK-ARM V5):1.1.在块开始的地方,首先定义变量,既在做任何赋值运算前定义完所有变量!
1.2.注意是块,没说是一定是函数头,但函数头确实是一个块开始的地方。另外,凡是左花括号“{开始的地方都是块开始的地方。
在块开始的地方先定义变量,再执行赋值语句。
2.如下图:

uCount是定义时给了初值,这是定义不是赋值。uTime是在定义时有个计算过程,usec不是确定的值,在翻译为汇编时必然有个计算过程,语法看起来是定义时给了初值,但其中有个计算过程,这个计算过程如果在定义uCount之前执行的话,就违反了上述的第1条。所以请按照第1条写代码。
3.如下图:
看为什么会出错(我的理解,可以讨论)!

在0x08024984地址处的代码是往r1写了0,然后在0x08024986地址处存入内存该r1=0;在0x08024988地址处执行了r1+=1;此时r1=1,接着在0x0802498a地址处存入内存该r1,此时存入内存内r1=1;然后在0x0802498c地址处判断r1和r0,r0既是uTime的值;显然r1小于r0,在0x0802498e地址处跳到了0x08024988地址处,此时r1=2,再在0x0802498a地址处存入内存和正确的汇编代码比较后你会发现此错误的汇编总是存入内存而没有从内存读!没有读内存也没什么问题,因为r1总是正确的加1了,只是缺少了一个从内存中读出r1再加的过程,这个看似“多此一举”的动作为什么会那么重要呢?
显然“错误的汇编没有按照__IO(既:volatile)的属性来处理r1(只完成了一半:存)!
按照volatile的规则,每次都需要从ram中(而不是寄存器中)读写数据,那么按此规则执行一定是正确的,否则可能会出现问题。
楼主可以再看下,该delay函数退出时r1的值是多少?以及谁会打断该函数?


最后,建议使用最新的编译器和ST官方的代码!!
HAL最新的usb-host中没有该USB_OTG_BSP_uDelay函数的使用,都是用的HAL_DELAY函数:

使用HAL_Delay:


一周热门 更多>