3

次の C コードで MISRA 2004 および MISRA 2012 の静的コード分析を実行しました。

BOOL_TYPE Strings_Are_Equal(const char *s1, const char *s2)
{
  BOOL_TYPE result = True;
  const char *str1 = s1;
  const char *str2 = s2;

  if (NULL == s1 || NULL == s2)
  {
    result = False;
  }
  else if (strlen(s1) != strlen(s2))
  {
    result = False;
  }
  else
  {
    while (*str1 != 0)
    {
      if(tolower(*str1++) != tolower(*str2++))
      {
        result = False;
        break;
      }
    }
  }

  return result;
}

PC-lintレポートから次の調査結果を得ました。 ここに画像の説明を入力

58行目と66行目のコードがどのように副作用に悩まされているのか、またどのように修正すればよいのか、誰か説明してもらえますか?

4

2 に答える 2

7

C 標準の正式な定義を使用している場合、関数を呼び出すと副作用が発生する可能性があります。

の特定のケースではstrlen(s1) != strlen(s2)、それらの関数内に害を及ぼす可能性のあるものは何もありません。staticたとえば、内部変数でそれらを実装するのは意味がありません。しかし、そのような内部変数が存在する場合、どの関数呼び出しが最初に実行されたかによって、評価の順序が異なる結果になる可能性があります。これがおそらく警告の背後にある理論的根拠です。

の場合tolower(*str1++) != tolower(*str2++)、++ 演算子からの 2 つの関数呼び出しの副作用と 2 つの変数代入の副作用の両方があり、1 つの式で合計 4 つになります。この特定のケースは安全ですが、そのようなコードは危険です。評価の順序に依存する可能性があり、完全に順序付けされていない ( のようにi=i++;) 重大なバグになる可能性さえあるからです。

関数の結果を一時変数に格納することで、これを解決します。++また、危険で無意味であり、別の MISRA ルールで禁止されているため、他のオペレーターと混同しないでください。

MISRA-C:2004 ルール 12.13

インクリメント (++) およびデクリメント (--) 演算子は、式内で他の演算子と混在させないでください。

于 2016-06-28T11:35:18.987 に答える
1

Lundinの優れた回答へのアドオンとして、MISRA準拠のアプローチは次のようになります。

    while (*str1 != 0)
    {
      // Condition should be a single sequence point
      // ... with no side effects
      if ( tolower(*str1) != tolower(*str2) )
      {
        result = false;
        break;
      }

      // Now increment pointers
      str1++;
      str2++;
    }

したがって、シーケンス ポイントを明確に区別できます。

于 2016-07-05T11:49:46.437 に答える