双方都有副作用吗?
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++;
}
这样你的序列点就区分的很清楚了
我运行 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++;
}
这样你的序列点就区分的很清楚了