Avoiding Arrow Anti-Pattern in MISRA-C
https://softwareengineering.stackexchange.com/questions/400414
-
03-03-2021 - |
题
For a safety-critical domain, with a code standard including the MISRA C 2004 guidelines, a "simple" piece of code becomes obtuse, chiefly because of the requirements both that all if()
statements have an else
and that there is only 1 return per function, and 1 break per loop. The original code looked like this:
while (bIncrementalOperation(&data))
{
vCode;
if (bCondition1)
{
u16Status |= u16STATUS_N1;
break;
}
if (bCondition2)
{
u8Var++;
}
if (bCondition3)
{
u16Status |= u16STATUS_N2;
break;
}
if (bCondition4)
{
break;
}
if (bCondition5)
{
vCode;
}
else
{
if (bCondition6)
{
break;
}
}
vCode;
}
Which is long because of formatting, but fairly terse. In comparison, to attempt compliance, it becomes:
bContinue = TRUE;
while (bContinue)
{
bContinue = bIncrementalOperation(&data);
if (!bContinue)
{
/* Normal exit condition: ... */
}
else
{
bContinue = bCondition1;
if (!bContinue)
{
u16Status |= u16STATUS_N1;
}
else
{
u8Var += (bCondition2) ? 1U : 0U;
bContinue = (bCondition3);
if (!bContinue)
{
u16Status |= u16STATUS_N2;
}
else
{
bContinue = bCondition4;
if (!bContinue)
{
/* Normal exit condition: .... */
}
else
{
if (bCondition5)
{
vCode;
}
else if (bCondition6)
{
/* Normal exit condition: ... */
break;
}
else
{
/* Continue to do IncrementalOperation */
}
vCode;
}
}
}
}
}
This pattern occurs often, especially in guarding functions which test against multiple failure modes, which leads to bugs. Is there a better pattern, that does not break the MISRA requirements?
解决方案
Upgrade to MISRA C:2012.
MISRA C:2012 does not contain Required Rule 14.9: "An if(expression) construct must be followed by a compound statement." or Required Rule 14.10: "All if/elseif must be terminated with an 'else' clause."
Problem solved.
Rule 15.5: "A function should have a single point of exit at the end" is Advisory, not Required. The primary motivation for a single exit point is to make it easier to get manual memory management correct; if your function doesn't allocate memory, you probably don't need it.
Note that you're probably reading MISRA C:2004 Rule 14.10 wrong. It only applies to else if
statements:
This rule applies whenever an
if
statement is followed by one or moreelse if
statements; the finalelse if
shall be followed by anelse
statement. In the case of a simpleif
statement then theelse
statement need not be included.The requirement for a final
else
statement is defensive programming. Theelse
statement shall either take appropriate action or contain a suitable comment as to why no action is taken. This is consistent with the requirement to have a finaldefault
clause in aswitch
statement.
MISRA C:2004 Rule 14.9 can be read as "Always use braces with if
statements," which is still good advice today.