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です。最初は、これが真実であるとは思えませんでしたが、Mark Wilkins が指摘するように、それがラップアラウンドすれば、真実である可能性があります。Timed_Val2>= Timed_Val1a

ただし、それらが等しい場合は 1 つだけTimed_Val2==0です。その場合は、読みやすくするために特別なケースとして抽出します。次に、2 つの>/<ステートメントを分解して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したがって、これは true if (if and only if) is 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

やや複雑なチェックの理由は、整数ロールオーバーの可能性があるためです。その場合は、チェックの 2 つの部分が必要です。特定の例が役立つ場合があります。たとえば、このシステムで long が 32 ビットで、の初期値Timed_Val1が 2^32-100 = 4294967196 の場合、2900Timed_Val2として計算されます。そのため、チェックのこの部分が必要になるのはそのような状況です。 :

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_msecval2 より大きい場合、またはロールオーバーして val1 より小さい場合に発生します。

ただし、選択された変数名は明らかに貧弱です。それらの名前を変更することは理にかなっています。

于 2012-11-05T20:59:33.137 に答える