V2659. MISRA. Switch statements should be well-formed.
This diagnostic rule is based on the MISRA (Motor Industry Software Reliability Association) software development guidelines.
This diagnostic rule is relevant only for C.
The switch
construct in C has fairly flexible syntax. A lack of strict rules can result in the creation of complex, unstructured code. To minimize errors and simplify code maintenance, MISRA introduces the concept of a "well-formed" switch
.
To explain what "well-formed" means, we will introduce two more definitions:
1. case-group
is a sequence of one or more consecutive case label
s (which may include default
), for example:
case 42:
// or
case 1: case 2: case 300:
// or
case 12:
default:
2. switch-clause
is one of the following:
- statements*
break;
- C90:
{
declarations* statements*break; }
- C99 and later:
{
(declarations | statements)*break; }
Where *
means repeat 0 or more times.
The example:
x = 5; y = 19; printf("%d", x); break;
// or
{ int x; int y; x = 5; y = x + 1; printf("%d", x); break; }
// or (except C90)
{ int x; x = 5; int y = x + 1; printf("%d", x); break; }
Considering the introduced definitions, a "well-formed" switch
can look as follows:
switch (expression)
{
case-group_1: switch-clause;
case-group_2: switch-clause;
....
case-group_n: switch-clause;
}
There are two additional requirements:
- The
default
label must appear either at the beginning of the firstcase-group
or at the end of the last one. - There must be at least two
case-group
s.
The examples of erroneous switch
statements:
switch (n)
{
case 1:
default: // <= (1)
case 2: n++; int x = 0; x++; break; // <= (2)
case 3: { n++; break; }
}
This example contains the following issues:
- the
default
label's position is incorrect: it must either be the first or the last label in the list; - there is an incorrect
switch-clause
aftercase 2
: it contains a declaration that is outside the block.
switch (n)
{
case 10:
case 20: break;
}
This example contains the following issues:
- the
default
label is missing; - since the second
case
label is included in the first one, the number ofcase-groups
is less than two. In this case,switch-case
does not make any sense.
switch (count % 4)
{
case 0: do { *to = *from++;
case 3: *to = *from++;
case 2: *to = *from++;
case 1: *to = *from++;
} while (--n > 0);
}
This example (the well-known Duff's device) contains the following issues:
- the incorrect
switch-clause
:break
is missing; - the incorrect
case-group
: thecase 3
,case 2
, andcase 1
labels are inside theswitch-clause
and form acase-group
sequence that is not directly inside theswitch-case
; - the
default
label is missing.
The example of a "well-formed" switch
:
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;
}