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++)++ 运算符同时存在两个函数调用副作用和两个变量赋值副作用的情况下,单个表达式中总共有 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 回答