0

我在产品线代码中遇到了一个超时功能,这让我非常困惑:

int TestTimeOut(unsigned long Timed_Val1, unsigned long Timed_Val2)
{
    Timed_Val2 = Timed_Val1 + (Timed_Val2 * 200);
    if (((Timed_Val1 > Timed_Val2) && (sys_msec < Timed_Val1) && (sys_msec > Timed_Val2)) || ((Timed_Val1 < Timed_Val2) && ((sys_msec < Timed_Val1) || (sys_msec > Timed_Val2))))
        return TRUE;
    return FALSE;
}

以下是它的使用方法:

unsigned long Timeout = sys_msec;
#define MAX_TIMEOUT   15L

    while (!com_eot(1))  //to check if some transmission in progress in COM1
        if (TestTimeOut(Timeout, MAX_TIMEOUT))
            return FALSE;
    return TRUE;

它是如何工作的?我对 TestTimeOut() 中的 3 行完全感到困惑。

4

2 回答 2

2

首先我重构出a局部b变量。

int TestTimeOut(unsigned long Timed_Val1, unsigned long Timed_Val2)
{
    Timed_Val2 = Timed_Val1 + (Timed_Val2 * 200);
    const int a = (Timed_Val1 > Timed_Val2) &&  (sys_msec < Timed_Val1) && (sys_msec > Timed_Val2);
    const int b = (Timed_Val1 < Timed_Val2) && ((sys_msec < Timed_Val1) || (sys_msec > Timed_Val2));
    return a || b;
}

现在这很有趣,是Timed_Val2基于Timed_Val1,他们都是unsigned如此。起初我看不出不可能是真的,但正如马克威尔金斯指出的那样,如果它环绕,它可以。Timed_Val2>= Timed_Val1a

然而,也只有一种情况它们是相等的,那就是当Timed_Val2==0我将把它作为一种特殊情况提取出来以提高可读性。然后我可以将两个>/<语句分解为if.

int TestTimeOut(unsigned long Timed_Val1, unsigned long Timed_Val2)
{
    if (Timed_Val2==0) return FALSE;

    {
      Timed_Val2 = Timed_Val1 + (Timed_Val2 * 200);

      if (Timed_Val1 > Timed_Val2)
      { //this happens when it wraps around past 2^32
        return (sys_msec < Timed_Val1) && (sys_msec > Timed_Val2);
      }
      else
      {
        return (sys_msec < Timed_Val1) || (sys_msec > Timed_Val2);
      }
    }
}

所以我会说这返回真当且仅当当且仅当sys_msec是 beforeTimed_Val1或 after Timed_Val1 + Timed_Val2 * 0.2 seconds

作为最后阶段,现在我将重命名变量并对其进行注释。

//Returns true iff time is before startTime_msec or after timeoutPeriods of 0.2 seconds
//startTime_msec - millisecond value compariable to sys_msec
//timeoutPeriods - the number of timeout periods of 0.2 seconds each
int TestTimeOut(const unsigned long startTime_msec, const unsigned long timeoutPeriods)
{
    if (timeoutPeriods==0) return FALSE;

    {
      const unsigned long maxTime_msec = startTime_msec + (timeoutPeriods * 200);
      if (startTime_msec > maxTime_msec)
      { //this happens when it wraps around past 2^32
        return (sys_msec < startTime_msec) && (sys_msec > maxTime_msec);
      }
      else
      {
        return (sys_msec < startTime_msec) || (sys_msec > maxTime_msec);
      }          
    }
}

这并不是说没有更好的方法可以做到这一点,但至少现在它是可读的。

于 2012-11-05T20:03:06.120 回答
2

检查有点复杂的原因是整数翻转的可能性。如果发生这种情况,那么它需要检查的两个部分。一个具体的例子可能会有所帮助。例如,如果一个 long 在这个系统上是 32 位的,并且初始值为Timed_Val12^32-100 = 4294967196,那么Timed_Val2将被计算为 2900。所以正是这种情况需要这部分检查:

if (((Timed_Val1 > Timed_Val2) && (sys_msec < Timed_Val1) && (sys_msec > Timed_Val2)) || 

在这种情况下,超时发生sys_msec在 val1 和 val2 之间。它需要大于 2900 且小于 4294967196。

条件的另一半是在计算中没有翻转时的“正常”情况Timed_Val2

((Timed_Val1 < Timed_Val2) && ((sys_msec < Timed_Val1) || (sys_msec > Timed_Val2))))

在这种情况下,超时发生在sys_msec大于 val2 或当它已经翻转并因此小于 val1 时。

但是,选择的变量名称肯定很差。重命名它们是有意义的。

于 2012-11-05T20:59:33.137 回答