A switch statement can be mixed with a block of code by starting the block in one case label, then having another case label within the block. The block can be pictured as spanning more than one case statement.
Section Subclause 6.8.4.2, paragraph 2, of the C Standard [ISO/IEC 9899:2011] says,
If a switch statement has an associated case or default label within the scope of an identifier with a variably modified type, the entire switch statement shall be within the scope of that identifier.154)
Footnote 154 says:
That is, the declaration either precedes the switch statement, or it follows the last case or default label associated with the switch that is in the block containing the declaration.
...
The examples here fall under the exception MSC17-C-EX2 in MSC17-C. Finish every set of statements associated with a case label with a break statement.
...
This example shows the use of the switch statement to jump into a for loop.:
| Code Block | ||||
|---|---|---|---|---|
| ||||
int f(int i) {
int j=0;
switch (i) {
case 1:
for(j=0;j<10;j++) {
//* noNo break,; process case 2 as well */
case 2: //* switch jumps inside the for block */
j++;
//* noNo break,; process case 3 as well */
case 3:
j++;
}
break;
default:
//* defaultDefault action */
break;
}
return j;
}
|
Implementation Details
When i = 1, the entire for loop is executed. When i = 2, two increments to j are made before the loop starts. When i = 3, one increment to j is made before the loop starts. The default case is no loop. Consequently, the function has the following behavior:
|
|
|---|---|
1 | 12 |
2 | 12 |
3 | 11 |
Other values | 0 |
Compliant
...
Solution
The compliant example solution separates the switch and for blocks.:
| Code Block | ||||
|---|---|---|---|---|
| ||||
int f(int i) {
int j=0;
switch (i) {
case 1:
//* noNo break,; process case 2 as well */
case 2:
j++;
//* noNo break,; process case 3 as well */
case 3:
j++;
break;
default:
//* defaultDefault action */
return j;
}
for(j++;j<10;j++) {
j+=2;
}
return j;
}
|
Noncompliant Code Example (Duff's Device)
Duff's device is a curious optimization applied to code intended to perform a serial copy. That is, it copies a series of bytes into one memory output in turn. A simple code to do this would be as follows:
| Code Block |
|---|
size_t count; /* mustMust be nonzero */ char *to; /* outputOutput destination */ char *from; /* Points to count bytes to copy */ do { *to = *from++; /* / * Note that the "to" pointer * is NOT incremented. */ } while (--count > 0); |
...
The code is widely considered to be legal valid C and C++ and is supported by all compliant compilers. When describing Duff's device, the creator [Duff 1988] noted,
Many people . . . have said that the worst feature of C is that switches don't break automatically before each case label. This code forms some sort of argument in that debate, but I'm not sure whether it's for or against.
Compliant
...
Solution (Duff's Device)
This is an alternate alternative implementation of Duff's device, which separates the switch statement and loop.:
| Code Block | ||||
|---|---|---|---|---|
| ||||
int n = (count + 7) / 8;
switch (count % 8) {
case 0: *to = *from++; /* fallFall through */
case 7: *to = *from++; /* fallFall through */
case 6: *to = *from++; /* fallFall through */
case 5: *to = *from++; /* fallFall through */
case 4: *to = *from++; /* fallFall through */
case 3: *to = *from++; /* fallFall through */
case 2: *to = *from++; /* fallFall through */
case 1: *to = *from++; /* fallFall through */
}
while (--n > 0) {
*to = *from++;
*to = *from++;
*to = *from++;
*to = *from++;
*to = *from++;
*to = *from++;
*to = *from++;
*to = *from++;
}
|
Risk Assessment
Recommendation | Severity | Likelihood | Detectable |
|---|
Repairable | Priority | Level |
|---|---|---|
MSC20-C | Medium |
Probable |
Yes |
No | P8 | L2 |
Automated Detection
Tool | Version | Checker | Description | ||||||
|---|---|---|---|---|---|---|---|---|---|
| Astrée |
| switch-label | Fully checked | ||||||
| CodeSonar |
| LANG.STRUCT.SW.MPC PARSE.BIH PARSE.BITB | Misplaced case | ||||||
|
swchsynt
Fully implemented
Related Guidelines
| CC2.MSC20 | Fully implemented | |||||||
| Helix QAC |
| C2019 | |||||||
| LDRA tool suite |
| 245 S | Fully implemented | ||||||
| PC-lint Plus |
| 646, 9055 | Fully supported | ||||||
| Polyspace Bug Finder |
| CERT C: Rec. MSC20-C | Checks for situations where switch label is not at the outermost level of switch statement body (rec. fully covered) | ||||||
| RuleChecker |
| switch-label | Fully checked | ||||||
| Security Reviewer - Static Reviewer |
| ctuNullPointer | Fully implemented | ||||||
| SonarQube C/C++ Plugin |
| S1036 |
Related Guidelines
| SEI CERT C++ Coding Standard | VOID |
| MSC20-CPP. Do not use a switch statement to transfer control into a complex block |
| MISRA |
| C:2012 | Rule 16.2 (required) |
Bibliography
| [ISO/IEC 9899:2011] |
Subclause 6.8.6.1, "The goto |
| Statement" |
| [ |
| Duff 1988] |
| Tom Duff on Duff's Device |
...
...