web-dev-qa-db-ja.com

MISRA-CでのArrow Anti-Patternの回避

MISRA C 2004ガイドラインを含むコード標準を持つ安全性が重要なドメインの場合、主にすべてのif()ステートメントにelseそして、関数ごとに1つの戻り値、およびループごとに1つのブレークがあることを示します。元のコードは次のようになりました。

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;
}

これはフォーマットのために長いですが、かなり簡潔です。比較すると、コンプライアンスを試みる場合、次のようになります。

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;
                }
            }
        }
    }
}

このパターンは頻繁に発生します。特に、複数の障害モードに対してテストを行う保護機能で発生し、バグが発生します。 MISRA要件に違反しない、より良いパターンはありますか?

3
JWCS

MISRA C:2012にアップグレードします。

MISRA C:2012には必須ルール14.9が含まれていません:「if(expression)構造の後には複合ステートメントが必要です。」または必須の規則14.10:「すべてのif/elseifは、 'else'句で終了する必要があります。」

問題が解決しました。

ルール15.5:「関数は最後に単一の出口点を持つ必要があります」は勧告ではなく必須です。単一の出口点の主な動機は手動のメモリ管理を正しく行うのを容易にするため。関数がメモリを割り当てない場合、おそらくそれは必要ありません。


MISRA C:2004 Rule 14.10を誤って読んでいることに注意してください。 else ifステートメントにのみ適用されます。

このルールは、ifステートメントの後に1つ以上のelse ifステートメントが続く場合に常に適用されます。最後のelse ifの後にはelseステートメントが続きます。 単純なifステートメントの場合、elseステートメントを含める必要はありません。

最後のelseステートメントの要件は、防御的プログラミングです。 elseステートメントは、適切なアクションを実行するか、アクションを実行しない理由に関する適切なコメントを含む必要があります。これは、defaultステートメントに最後のswitch句を含めるという要件と一致しています。

MISRA C:2004ルール14.9は、「ifステートメントでは常に中括弧を使用する」と読むことができます。

9
Robert Harvey