...
This noncompliant code example fails to test for conditions where a
is neither b
nor c
. This may be the correct behavior in this case, but failure to account for all the values of a
can result in logic errors if a
unexpectedly assumes a different value.
Code Block | ||||
---|---|---|---|---|
| ||||
if (a == b) { /* ... */ } else if (a == c) { /* ... */ } |
...
This compliant solution explicitly checks for the unexpected condition and handles it appropriately.
Code Block | ||||
---|---|---|---|---|
| ||||
if (a == b) { /* ... */ } else if (a == c) { /* ... */ } else { /* handle error condition */ } |
...
The following noncompliant code example fails to consider all possible cases. Failure to account for all valid values of type Color
will result in a 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 { Red, Green, Blue } Color; const char* f(Color c) { switch (c) { case Red: return "Red"; case Green: return "Green"; case Blue: return "Blue"; } } void g() { Color unknown = (Color)123; puts(f(unknown)); } |
...
The compliant solution below takes care to provide the default
label to handle all valid values of type Color
:
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"; default: return "Unknown color"; /* necessary */ } } |
...
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 */ } |
...
The flaw in the code occurs when days
has the value 366 because the loop never terminates. This bug manifested itself on the 366th day of 2008, which was the first leap year in which this code was active.
Code Block | ||||
---|---|---|---|---|
| ||||
#define ORIGINYEAR 1980 UINT32 days = /* number of days since January 1, 1980 */ int year = ORIGINYEAR; /* ... */ while (days > 365) { if (IsLeapYear(year)) { if (days > 366) { days -= 366; year += 1; } } else { days -= 365; year += 1; } } |
...
This proposed rewrite is provided by http://www.aeroxp.org/2009/01/lesson-on-infinite-loops. The loop is guaranteed to exit, as days
decreases for each iteration of the loop, unless the while
condition fails, and the loop terminates.
Code Block | ||||
---|---|---|---|---|
| ||||
#define ORIGINYEAR 1980 UINT32 days = /* input parameter */ int year = ORIGINYEAR; /* ... */ int daysThisYear = (IsLeapYear(year) ? 366 : 365); while (days > daysThisYear) { days -= daysThisYear; year += 1; daysThisYear = (IsLeapYear(year) ? 366 : 365); } |
...