﻿# V2659\. MISRA\. Switch statements should be well\-formed\.

Диагностическое правило основано на руководстве [MISRA](https://misra.org.uk/) \(Motor Industry Software Reliability Association\) по разработке программного обеспечения\.

Конструкция switch обладает достаточно свободным синтаксисом\. Отсутствие строгих правил может привести к написанию сложного неструктурированного кода\. Для уменьшения вероятности допущения ошибки, а также для упрощения поддержки кода, стандарты MISRA обязывают формировать корректные \("well\-formed"\) конструкции switch\.

Чтобы пояснить, что такое "well\-formed", введём ещё два определения:

1\. `case-group` — последовательность из одного и более идущих подряд `case label` \(которые могут включать `default`\), например:

```cpp
case 42:
// или
case 1: case 2: case 300:
// или
case 12:
default:
```

2\. `switch-clause` — одно из следующего:

* Любая версия C: `statement*` `break;`\.
* C90: `{` `declaration*` `statement*` `break;` `}`\.
* C99 и другие: `{ ` `(declaration | statement)*` `break;` `}`\.
* C\+\+: `(declaration | statement)*` `termination-statement`\.

Где `*` означает повторение 0 или более раз\.

**Примечание**: MISRA C\+\+ считает декларации исполняемыми инструкциями, поэтому блок `{...}` вокруг объявлений после метки `case` не требуется\. Ветвь должна завершаться `termination-statement` — это инструкции `break`, `return`, `throw`, `continue`, `goto` или атрибут `[[fallthrough]]`\.

Примеры:

```cpp
x = 5; y = 19; printf("%d", x); break;
// или
{ int x; int y; x = 5; y = x + 1; printf("%d", x); break; }
// или (кроме C90)
{ int x; x = 5; int y = x + 1; printf("%d", x); break; }
```

С учётом введённых определений "well\-formed" `switch` можно представить в следующем виде:

```cpp
switch (expression)
{
case-group_1:
  switch-clause
case-group_2:
  switch-clause
....
case-group_n:
  switch-clause
}
```

Также есть два дополнительных требования:

* метка `default` обязана присутствовать и либо стоять в начале первой `case-group`, либо в конце последней;
* Количество `case-group` должно быть не меньше двух\.

Пример N1\. Некорректный `switch statement`:

```cpp
switch (n)
{
case 1:
default:                            // <= (1)
case 2: n++; int x = 0; x++; break; // <= (2)
case 3: { n++; break; }
}
```

В примере N1 присутствуют следующие нарушения:

* неправильно расположена метка `default`: она должна быть либо первой в списке меток, либо последней;
* некорректный `switch-clause` после `case 2`: он содержит декларацию, которая не находится внутри блока\.

Пример N2\. Некорректный `switch statement`:

```cpp
switch (n) 
{
case 10:
case 20: break;
}
```

В примере N2 присутствуют следующие нарушения:

* отсутствует метка `default`;
* так как вторая метка `case` входит в первую, то количество `case-group` меньше двух\. В таком случае `switch-case` не имеет смысла\.

Пример N3\. Некорректный `switch statement`:

```cpp
switch (count % 4) 
{
  case 0: do { *to = *from++;
  case 3:      *to = *from++;
  case 2:      *to = *from++;
  case 1:      *to = *from++;
             } while (--n > 0);
}
```

В примере N3 \(знаменитый [метод Даффа](https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%BE%D0%B4_%D0%94%D0%B0%D1%84%D1%84%D0%B0)\) присутствуют следующие нарушения:

* некорректный `switch-clause`: отсутствует `break`;
* некорректный `case-group`: метки `case 3`, `case 2`и `case 1` находятся внутри `switch-clause` и образуют последовательность `case-group`, которая не находится непосредственно внутри `switch-case`;
* отсутствует метка `default`\.

Пример N4\. Корректно сформированная конструкции `switch`:

```cpp
switch (n) 
{
  case 1: case 2: { n = 5; } break;
  case 10: 
  case 20: break;
  case 30: { int x; x = 4; printf("%d", x); break; }
  default: if (n > 6) { n++; } break; 
}
```