...
Noncompliant Code Example (Switch)
This The following noncompliant code example fails to consider all possible cases. This can be the correct behavior in this case, but failure Failure to account for all the valid values of widget_ type can Color
will result in logic errors if widget_type
unexpectedly assumes a different value or if its valid range is expanded during code maintenance, and the programmer overlooks the need to add a case to the switch.This is particularly problematic in C because an identifier declared as an enumeration constant has type int
. As a result, a programmer can accidentally assign an arbitrary integer value to an enum
type, as shown in this examplea logic error. Since valid values of an enumerated type include all those of its underlying integer type, unless enumeration constants have been provided for all those values the default
label is appropriate and necessary.
Code Block | ||
---|---|---|
| ||
typedef enum WidgetEnum { WE_WRed, WE_XGreen, WE_Y, WE_Z Blue } widget_typeColor; widget_type = 45; switch (widget_typeconst char* f(Color c) { switch (c) { case WE_XRed: return "Red"; /* ... */ break; case WE_Y: /* ... */ break; case WE_Z: /* ... */ break case Green: return "Green"; case Blue: return "Blue"; } } void g() { Color unknown = (Color)123; puts(f(unknown)); } |
Implementation Details
...
Compliant Solution (Switch)
This The compliant solution explicitly checks for the unexpected condition by adding a default
clause to the switch statement.below takes care to provide the default
label to handle all valid values of type Color
:
Code Block | ||
---|---|---|
| ||
typedef enum WidgetEnum { WE_WRed, WE_XGreen, WE_Y, WE_ZBlue } widget_typeColor; widget_type = WE_X; switch (widget_typeconst char* f(Color c) { case WE_W: /* ... */switch (c) { break; case WE_XRed: /* ... */ break; return "Red"; case WE_YGreen: /* ... */ break; return "Green"; case WE_ZBlue: /* ... */ break; return "Blue"; default: return /* can't happen */ /* handle error condition"Unknown color"; /* necessary */ break;} } |
Adding Note that adding a default case to a switch statement, even when all possible switch labels are specified, is an allowable exception (MSC07-EX1) to recommendation MSC07-C. Detect and remove dead code, as the unreachable code is added as a precautionary measure..
An alternative compliant solution to the noncompliant code example above is to provide a return
statement after the switch
statement. Note, however, that this solution may not be appropriate in all situations.
Code Block | ||
---|---|---|
| ||
typedef enum { Red, Green, Blue } Color;
const char* f(Color c) {
switch (c) {
case Red: return "Red";
case Green: return "Green";
case Blue: return "Blue";
}
return "Unknown color"; /* necessary */
}
|
Historical Discussion
This practice has been a subject of debate for some time, but a clear direction has emerged.
...