For 循环应该是良构的

For loop should be well-formed

MISRA C-2012 控制流表达式(MISRA C-2012 规则 14.2)

  1. 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;
  1. 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 将规则从一个版本重新编号到下一版本,这是一个必要的更改,造成了一些混乱。

  • 规则在开源中不可用。这将有助于传播一些好的做法,但可以说可以防止一些有问题的做法。