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 подразумевает повышенные требования к безопасности кода.