MISRA C 2012 Правило 16.1 Все операторы переключения должны быть правильно сформированы

Я пытаюсь избавиться от нарушения правил 16.1 из моего кода.

Образец кода:

switch (cmd) {
    case ADD:
        result = add(op1, op2);
        break;
    case SUB: 
        if (!flag) {    // Problem here!
            break;     
        }
        //Fallthrough
    case ALU_CMD_SUB:
        result = sub(op1, op2);
        .
        .
        .
        .
        .
        .

        break;
    case ALU_CMD_DIV:
        result = divide(op1, op2);
        break;
    case ALU_CMD_EXP:
        result = (int32_t)expo((uint32_t)op1, (uint32_t)op2);
        break;
    default:
        incr_default(&default_cond);
        //fix for the violation: insert a break statement
        break;
}     

Здесь корпус переключателя с SUB не очень хорошо сформирован.

Есть ли способ исправить эту проблему без большого шума в коде.

Это также нарушает правило 16.3, где регистр переключателя не имеет оператора break.

4 ответа

Это довольно просто исправить:

case SUB: 
   SUB_stuff();
   ALU_CMD_SUB_stuff();
   break;

case ALU_CMD_SUB:
   ALU_CMD_SUB_stuff();
   break;

Позвольте компилятору беспокоиться о том, как перевести вышеприведенное в машинный код с минимальным количеством ветвей.

Это очень здравые правила MISRA, так как наличие "провала" очень опасно и почти всегда является результатом либо забвения break случайно или из-за плохого базового дизайна. Раньше я был фанатом "провала в работе", но в конце концов понял, что необходимость в использовании таких провалов возникает из-за грязного мышления в другом месте программы.

Точно так же, его использование в целях оптимизации кода (например, "Устройство Даффа") - вещь 80-х годов, и в настоящее время это не что иное, как преждевременная оптимизация.

В контексте, соблюдая букву закона MISRA (Правило 16.3), вы можете рассмотреть:

switch (cmd) {
    case ADD:
        result = add(op1, op2);
        break;
    case SUB: 
    case ALU_CMD_SUB:
        if (cmd == SUB && !flag) {
            break;     
        }
        result = sub(op1, op2);
        .
        .
        .    
        break;
    …
}

или возможно:

switch (cmd) {
    case ADD:
        result = add(op1, op2);
        break;
    case SUB: 
    case ALU_CMD_SUB:
        if (cmd == ALU_CMD_SUB || flag) {
            result = sub(op1, op2);
            .
            .
            .
        }
        break;
    …
}

Самым простым ответом на вопрос, если это действительно преднамеренный прорыв, является поднятие отклонения.

Попытки обойти правило, пытаясь написать умный код, делают вещи менее понятными и менее понятными - отклонение дает понять, что вы хотите сделать, и означает, что будущие сопровождающие не совершают ошибок.

В дополнение к следующему изданию стандарта C предлагается добавить аннотацию [[fallthrough]] передать, что это ожидаемое поведение! Я почти уверен, что MISRA C распознает этот атрибут сразу после публикации, а правило 16.3 обновлено...

Падение - допустимая конструкция в C - она ​​может повысить эффективность кода. Одна из радостей обладания большим опытом - это знать, когда можно нарушать "правила". В этом случае, когда важна хорошая разработка и безопасность кода (*), задокументируйте, почему это правило было нарушено на этом этапе.

Я предполагаю, что в этом случае if !flag элемент не должен быть проверен под ALU_CMD_SUBи что SUB элемент является действительным предшественником для выполнения ALU_CMD_SUB элемент.

(*) Принятие MISRA подразумевает повышенные требования к безопасности кода.

Другие вопросы по тегам