双方都有副作用吗?

Both sides have side effects?

我运行 MISRA 2004 和 MISRA 2012 的静态代码分析如下 C 代码:

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 行的代码是如何产生副作用的吗?我应该如何更正它?

在使用 C 标准的正式定义时,调用函数可能会引发副作用

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

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

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

MISRA-C:2004 Rule 12.13

The increment (++) and decrement (--) operators should not be mixed with other operators in an expression.

作为 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++;
    }

这样你的序列点就区分的很清楚了