For 循环应该是良构的
For loop should be well-formed
MISRA C-2012 控制流表达式(MISRA C-2012 规则 14.2)
- misra_c_2012_rule_14_2_violation: for循环子句中使用的表达式i在循环体中被修改
for( i = 0; i < FLASH; i++ )
{
if( name.see[i] == 0xFF )
{
name.see[ i ] = faultId | mnemonicType;
- modify_expr:修改表达式i.
i = FLASH-1; /* terminate loop */
}
}
不允许在循环体内修改循环迭代器 i
,这样做是毫无意义的,也是非常糟糕的做法。将混淆代码 i = FLASH-1;
替换为 break;
.
这个for循环
for( i = 0; i < FLASH; i++ )
{
if( name.see[i] == 0xFF )
{
name.see[ i ] = faultId | mnemonicType;
i = FLASH-1; /* terminate loop */
}
}
代码的读者不清楚。
就算你会写
for( i = 0; i < FLASH; i++ )
{
if( name.see[i] == 0xFF )
{
name.see[ i ] = faultId | mnemonicType;
break;
}
}
然后使用 break 语句不是一个好方法。每个代码块应该有一个入口点和一个出口点。
其实你需要的是找到一个满足条件的元素
name.see[i] == 0xFF
是否存在这样的元素然后更改它。
所以最好写一个while循环而不是下面的for循环
i = 0;
wjile ( i < FLASH && name.see[i] != 0xFF ) i++
if ( i != FLASH ) name.see[ i ] = faultId | mnemonicType;
这种方法的优点是可以将 while 循环原样形成为在数组中查找元素的函数的主体。只需添加 return 语句
就足够了
return i;
Misra C 2004 规则 13.6(2012 版为 14.2)说
Numeric variables being used within a for
loop for iteration counting shall not be modified in the body of the loop.
代码修改 i
以完成 for
循环(如注释所确认)。这违反了规则。
Misra C 2004 规则 14.6 说:
For any iteration statement there shall be at most one break
statement used for loop termination.
因此您可以用一个简单的 break
语句替换有问题的代码并且仍然符合:
for (i = 0; i < FLASH; i++) {
if (name.see[i] == 0xFF) {
name.see[i] = faultId | mnemonicType;
break;
}
}
然而 Misra 说只有在循环中有 single break
语句时才能这样做。如果你想测试 2 个不同的案例,以不同的方式处理它们并打破每个案例的循环怎么办?使用 2 break
语句似乎是一个明显的选择,但为了合规性,您需要添加一个额外的变量 do_break
,将其设置在您想要中断的地方并在结束时测试一次body 来执行 break
语句。恕我直言,这不是一个很好的做法...
注意这些关于 Misra C 编码标准的事实:
Misra 将规则从一个版本重新编号到下一版本,这是一个必要的更改,造成了一些混乱。
规则在开源中不可用。这将有助于传播一些好的做法,但可以说可以防止一些有问题的做法。
MISRA C-2012 控制流表达式(MISRA C-2012 规则 14.2)
- misra_c_2012_rule_14_2_violation: for循环子句中使用的表达式i在循环体中被修改
for( i = 0; i < FLASH; i++ )
{
if( name.see[i] == 0xFF )
{
name.see[ i ] = faultId | mnemonicType;
- modify_expr:修改表达式i.
i = FLASH-1; /* terminate loop */
}
}
不允许在循环体内修改循环迭代器 i
,这样做是毫无意义的,也是非常糟糕的做法。将混淆代码 i = FLASH-1;
替换为 break;
.
这个for循环
for( i = 0; i < FLASH; i++ )
{
if( name.see[i] == 0xFF )
{
name.see[ i ] = faultId | mnemonicType;
i = FLASH-1; /* terminate loop */
}
}
代码的读者不清楚。
就算你会写
for( i = 0; i < FLASH; i++ )
{
if( name.see[i] == 0xFF )
{
name.see[ i ] = faultId | mnemonicType;
break;
}
}
然后使用 break 语句不是一个好方法。每个代码块应该有一个入口点和一个出口点。
其实你需要的是找到一个满足条件的元素
name.see[i] == 0xFF
是否存在这样的元素然后更改它。
所以最好写一个while循环而不是下面的for循环
i = 0;
wjile ( i < FLASH && name.see[i] != 0xFF ) i++
if ( i != FLASH ) name.see[ i ] = faultId | mnemonicType;
这种方法的优点是可以将 while 循环原样形成为在数组中查找元素的函数的主体。只需添加 return 语句
就足够了return i;
Misra C 2004 规则 13.6(2012 版为 14.2)说
Numeric variables being used within a
for
loop for iteration counting shall not be modified in the body of the loop.
代码修改 i
以完成 for
循环(如注释所确认)。这违反了规则。
Misra C 2004 规则 14.6 说:
For any iteration statement there shall be at most one
break
statement used for loop termination.
因此您可以用一个简单的 break
语句替换有问题的代码并且仍然符合:
for (i = 0; i < FLASH; i++) {
if (name.see[i] == 0xFF) {
name.see[i] = faultId | mnemonicType;
break;
}
}
然而 Misra 说只有在循环中有 single break
语句时才能这样做。如果你想测试 2 个不同的案例,以不同的方式处理它们并打破每个案例的循环怎么办?使用 2 break
语句似乎是一个明显的选择,但为了合规性,您需要添加一个额外的变量 do_break
,将其设置在您想要中断的地方并在结束时测试一次body 来执行 break
语句。恕我直言,这不是一个很好的做法...
注意这些关于 Misra C 编码标准的事实:
Misra 将规则从一个版本重新编号到下一版本,这是一个必要的更改,造成了一些混乱。
规则在开源中不可用。这将有助于传播一些好的做法,但可以说可以防止一些有问题的做法。