依靠溢出是危险的吗?

Fid*_*its -1 c c++ counter timer delay

以下是我在固件中找到的延迟功能.它看起来有点危险,或者至少让读者感到困惑.

全局变量

static int32u masterTimerCounter; // 32-bit unsigned timer counter
Run Code Online (Sandbox Code Playgroud)

系统勾选中断处理程序

/* Called Every Millisecond */
void sysTickIrqHandler(void)
{
    masterTimerCounter++;
}
Run Code Online (Sandbox Code Playgroud)

设置定时器到期功能

void setTimerExpiration(int32u *timerExpiration, int32u delay)
{
    *timerExpiration = masterTimerCounter + delay;
}
Run Code Online (Sandbox Code Playgroud)

检查定时器是否过期功能

boolean timerExpired(int32u timerExpiration, int32u delay)
{
    if((masterTimerCounter - timerExpiration) < delay)
        return TRUE; // Timer has expired
    else
        return FALSE; // Timer still active
}
Run Code Online (Sandbox Code Playgroud)

设置定时器提取和阻止直到定时器到期

int32u timerExpiration;
setTimerExpiration(&timerExpiration, 15); // Set expiration timer to 15 milliseconds
while(!timerExpired(timerExpiration, 15) // Block until timer has expired
    continue; 
Run Code Online (Sandbox Code Playgroud)

如你所见timerExpired(),masterTimerCounter减去timerExpiration.如果计时器尚未到期,则计算将导致非常大的数量(因为两个操作数都是无符号数).当计时器到期时,计算将导致小于延迟量的值.

虽然这似乎工作正常,但似乎它可能是危险的,或者至少会让读者感到困惑(我必须多次阅读才能理解原始程序员的意图).

如果我必须编写与此类似的东西,我将按timerExpired如下方式定义函数:

boolean timerExpired(int32u timerExpiration)
{
    if(timerExpiration > masterTimerCounter)
        return FALSE; // Timer still active
    else
        return TRUE; // Timer has expired
}
Run Code Online (Sandbox Code Playgroud)

我应该重新定义'timerExpired()`吗?

注意:功能和变量名称已更改以保护无辜者.

Use*_*ess 5

请注意,原始逻辑类似于:是过去的绝对到期时间,但不到完整的延迟时间段.也许我们可以像最近的计时器火一样松散地表达它.

您修改的逻辑只是过去的绝对到期时间,这是不同的.


通过简单地添加timerExpiration不等式的每一边,您可以轻而易举地避免下溢的风险:

boolean timerExpired(int32u timerExpiration, int32u delay)
{
// WAS: (masterTimerCounter - timerExpiration) < delay
    if(masterTimerCounter < timerExpiration + delay)
        return TRUE; // Timer has expired
    else
        return FALSE; // Timer still active
}
Run Code Online (Sandbox Code Playgroud)

但是这会改变行为,因为如果你说原作将永远是假的masterTimerCounter < timerExpiration.您可以通过显式检查来获得原始行为,而不会产生令人困惑的下溢:

boolean timerExpired(int32u timerExpiration, int32u delay)
{
    if(masterTimerCounter > timerExpiration &&       // did it expire ...
       masterTimerCounter < timerExpiration + delay) // ... recently?
        return TRUE; // Timer has expired
    else
        return FALSE; // Timer still active
}
Run Code Online (Sandbox Code Playgroud)