我使用以下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;
}
有人可以解释第58和66行的代码是如何受到副作用的,我该如何纠正?
答案 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++;
}
因此,您的序列点之间有明显的区别。