MISRA Discussion Forums

Full Version: Switches, default, and enums
You're currently viewing a stripped down version of our content. View the full version with proper formatting.
Rule 15.3 requires every switch to end with a default clause. While this is usually a good idea, it undermines the technique of using enums for switch control and having the compiler catch unused or unhandled values. For example:

Code:
typedef enum {
      red,
      green,
      blue
   } color_t;

   void f(color_t color) {
      switch (color) {
      case red:
         /* do something */
         break;
      case green:
         /* do something */
         break;
   }
Many compilers and certainly most lints will generate a warning when compiling the function f noting that not all enum values are handled. When the typedef and the switch are in different files, this can be quite helpful. When the enum is handled by switches in multiple source files, this structure allows the compiler to catch unmodified switches when a new enum value is added. If there was a default case in this switch, the compiler would not complain.

With that in mind, I suggest that rule 15.3 be revised by adding, \"except where the switch expression is an enum\" to the end. I might also add a advisory rule encouraging switch expressions to be enums.

Any thoughts?
ChrisNelson Wrote:Rule 15.3 requires every switch to end with a default clause. [...] For example:

Code:
typedef enum {
      red,
      green,
      blue
   } color_t;

   void f(color_t color) {
      switch (color) {
      case red:
         /* do something */
         break;
      case green:
         /* do something */
         break;
   }
Many compilers and certainly most lints will generate a warning when compiling the function f noting that not all enum values are handled. [...]
With that in mind, I suggest that rule 15.3 be revised by adding, "except where the switch expression is an enum" to the end. I might also add a advisory rule encouraging switch expressions to be enums.

Any thoughts?

While I have some sympathy with this position, we have to realise that enums are just ints beneath, and there's nothing much to stop you writing

Code:
f((color_t) -1);

so we have to balance the static checking offered by the lint against the dynamic checking available through a suitable default case.

One possibility might be to hide the default case from the lint; although this would bring up another set of issues needing justification.

As usual, where there is some debate in the issue, it is probably best if you raise a deviation to the rule containing your proviso ("except where the switch expression is an enum") with appropriate justification.

stephen
ChrisNelson Wrote:Many compilers and certainly most lints...
Then it cannot be a MISRA rules because it is not "all compiler", and this is not applicable for all compiler because this behavior (generat a warning in this case) is unspecified by the ISO 9899.

That could only be a project/company deviation.
sparker's reply is consistant with the view of the working group.
Do I understand correctly that even if the cases of a switch statement exhaust all elements of an enum the default statement is not \"unreachable\" in the sense of MISRA-2004:14.1 / MISRA 98:52 due to the argument given by sparker?

George Brown

When writing code for safety-critical systems, I have always considered treating all RAM locations to be \"volatile\" in nature. If I have code which can set a 16 bit unsigned integer (represeting an enum) explicitly to the values of 0, 1, 2, and 3, I also always handle the cases of it being any other value the storage may select, i.e. 4 to 65535.

Given
Code:
typedef enum {
   red,
   green,
   blue
} color_t;

   ...
   color_t color;
   ...
   color = red;
   ...
   {
      switch (color) {
      case red:
         /* do something */
         break;
      case green:
         /* do something */
         break;
      case blue:
         /* do something */
   }

Treat color to be volatile, and assume that a failure mechanisum WILL exist to randomly set it.
Given this, the need for the default clause is not in question. (imho)

George
I agree completely with George, an important purpose of the rule is defensive programming against \"RAM noise\", ie in a safety-critical system the RAM can't be trusted to keep its values during long periods of time. Also, if there is an undetected runtime bug altering a memory location unexpectedly, the bug can be detected, and damage caused by it avoided, if using this method.

The same argument can be used for justifying rule 14.10 saying that you must end an \"if...else if\" with \"else\".