双方都有副作用吗?

时间:2016-06-28 11:24:55

标签: c lint side-effects misra pc-lint

我使用以下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报告中得到以下结论: enter image description here

有人可以解释第58和66行的代码是如何受到副作用的,我该如何纠正?

2 个答案:

答案 0 :(得分:7)

在使用C标准的正式定义时,调用函数可以调用副作用

strlen(s1) != strlen(s2)的特定情况下,这些功能中没有任何内容可能造成伤害。用例如内部static变量实现它们是没有意义的。但是如果存在这样的内部变量,则评估顺序可以根据首先执行的函数调用给出不同的结果。这可能是警告背后的基本原理。

tolower(*str1++) != tolower(*str2++)的情况下,++运算符有两个函数调用副作用和两个变量赋值副作用,在单个表达式中总共有4个。尽管这种特殊情况是安全的,但这样的代码是危险的,因为它可能取决于评估的顺序,甚至完全没有排序(如i=i++;),这将是一个严重的错误。

通过将函数结果存储在临时变量中来解决此问题。永远不要将++与其他运营商混在一起,因为这既危险又毫无意义,又被另一条MISRA规则所禁止:

  

MISRA-C:2004 Rule 12.13

     

不应混合增量(++)和减量( - )运算符   与表达式中的其他运算符一起使用。

答案 1 :(得分: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++;
    }

因此,您的序列点之间有明显的区别。