Home > OS >  For loop should be well-formed
For loop should be well-formed

Time:12-02

MISRA C-2012 Control Flow Expressions (MISRA C-2012 Rule 14.2)

  1. misra_c_2012_rule_14_2_violation: The expression i used in the for loop clauses is modified in the loop body.
  for( i = 0; i < FLASH; i   )
  {
    if( name.see[i] == 0xFF )
    {
      name.see[ i ] = faultId | mnemonicType;
  1. modify_expr: Modifying the expression i.
      i =  FLASH-1; /* terminate loop */
    }    
  }  

CodePudding user response:

You aren't allowed to modify the loop iterator i inside the loop body, doing so is senseless and very bad practice. Replace the obfuscated code i = FLASH-1; with break;.

CodePudding user response:

This for loop

  for( i = 0; i < FLASH; i   )
  {
    if( name.see[i] == 0xFF )
    {
      name.see[ i ] = faultId | mnemonicType;
      i =  FLASH-1; /* terminate loop */
    }    
  }

is not clear for readers of the code.

Even if you will write

  for( i = 0; i < FLASH; i   )
  {
    if( name.see[i] == 0xFF )
    {
      name.see[ i ] = faultId | mnemonicType;
      break;
    }    
  }

then using the break statement is not a good approach. Each code block should have one entry point and one exit point.

In fact what you need is to find an element that satisfies the condition

name.see[i] == 0xFF

and is such an element exists then change it.

So it is better to write a while loop instead of the for loop the following way

  i = 0;

  wjile ( i < FLASH && name.see[i] != 0xFF ) i  

  if ( i != FLASH ) name.see[ i ] = faultId | mnemonicType;

The advantage of this approach is that the while loop as is can be formed as a body of a function that finds an element in the array. It will be enough just to add the return statement

return i;

CodePudding user response:

Misra C 2004 rule 13.6 (14.2 in the 2012 edition) says

Numeric variables being used within a for loop for iteration counting shall not be modified in the body of the loop.

The code modifies i in order to break for the loop (as the comment confirms). This is a violation of the rule

Misra C 2004 rule 14.6 says:

For any iteration statement there shall be at most one break statement used for loop termination.

Hence you can replace the offending code with a simple break statement:

    for (i = 0; i < FLASH; i  ) {
        if (name.see[i] == 0xFF) {
            name.see[i] = faultId | mnemonicType;
            break;
        }
    }    

Yet Misra says you can only do this if there is a single break statement in the loop. What if you want to test 2 different cases, handle them differently and break the loop on each of them. Using 2 break statements seems an obvious choice, but for compliance you would need to add an extra variable do_break, set it in the places where you want to break and test it just once at the end of the body to execute the break statement. Not a very good practice IMHO...

Note these facts about Misra C coding standards:

  • Misra renumbered the rules from one edition to the next, a necessary change creating some confusion.

  • The rules are not available in open source. This would help spread some good practices, but arguably prevented some questionable ones.

  • Related