switch case example ambiguity / error

The example code in the reference for switch case is ambiguous / has an error.

Making the simplest expansion...

int var = 0;

void setup() {
}

void loop() {

 switch (var) {
    case 1:
      //do something when var equals 1
      break;
    case 2:
      //do something when var equals 2
      break;
    default: 
      // if nothing else matches, do the default
      // default is optional
  }

}

.. produces an "expected primary-expression before '}' token" error.

For someone not used to C (me) it took a while to work out that while the default label is indeed optional, if it is included, there must be a statement before the switch statement's closing '}' - you cannot have, as in the example, an empty default case.

(It did not help that most of the C tutorials I can find don't mention this either, but converting to C by losing the setup() function and renaming loop() to main() and compiling the above with gcc produced a 'label at end of compound statement' error.)

As not all languages treat an empty default case as an error, the example should mention this 'feature'.

I usually put a break; in the default: clause as well. I've found that people ask less questions when faced with the pattern 'always include the break keyword when defining a switch label' as opposed the fact that default: expect some compound statement to execute. (Not that this is not logical: why should you do a default action if that action is to do nothing?)

For the arduino reference I suggest:

int var = 0; //some variable

switch (var) {
  case 1:
    //do something when var equals 1
    break;
  case 2:
    //do something when var equals 2
    break;
  default:
    // if nothing else matches, do the default
    // default is optional
    break;
}

(Not that this is not logical: why should you do a default action if that action is to do nothing?)

Because this:

int var = 0; //some variable

switch (var) {
  default:
    // if nothing else matches, do the default
    // default is optional
    break;

  case 1:
    //do something when var equals 1
    break;
  case 2:
    //do something when var equals 2
    break;
}

If you don't have the break, the default action is the same as "case 1:".

I work on code where switches may extend over many hundreds of lines - it could make inspection easier if the default came first.

I work on code where switches may extend over many hundreds of lines

Why? That’s what subroutines are for.

Given that..

switch (var) {
    default:
      // if nothing else matches, do the default
      // and fall through to next case
    case 1:
      // fall through when var equals 1
    case 2:
      //do something when var equals 2
      break;
  }

.. is legal (but not particularly useful as it stands :) ) what about something like 'the last label in the statement must not be empty' or 'every label but the last can be empty'?

Edit: Thinking about it further...

"Although all other labels can be empty (in which case control falls through to the next label, as with any other label without a 'break' statement), the last label must contain at least one statement."

?

You can add "even a logically unnecessary 'break' statement" if you like :)

(Not that this is not logical: why should you do a default action if that action is to do nothing?)

Why, if the action is nothing, should you have to include a statement? :)

Given that all other labels except the last can be empty, why should this not be the case with the last one?

I discovered this 'feature' when I commented out the default action and found it would not compile.

Why? That's what subroutines are for

?

Most cases are simply calls to subroutines, or simple assignments. Still lots and lots of them. (Application: Message handling in a large real-time OS)

@AWOL Makes sense, I guess. I would look for a way, though, to sort some of the cases. Maybe the overhead of doing that isn't practical in all cases, though.

Thank you for responding, though. Tone of voice, etc. gets lost when typing. I wasn't asking why as in why the heck would you do that. I was asking why for educational purposes. Re-reading my post, I can see that that wasn't clear.

(Not that this [this being ‘appending an empty default: block to the switch-case’] is not logical: why should you do a default action if that action is to do nothing?)

Why, if the action is nothing, should you have to include a statement? :slight_smile:

(Emphasis is mine).

Ehm… You do not have to, and I think you should not do it.

[edit]
OffTopic @AWOL:
This was interesting.

Could you not define a function as being a msgProcess and then have an array of such msgProcess(ors) and later index them according to msg type?

Sorry for this, but my inner software architect could not keep its fingers from typing:

typedef void result; //i do not know what return type you use
typedef result (*msgProcess)(Message *msg);//neither the name of the Message datatype

result processType0(Message *msg){ /*do something related to type 0*/ }
result processType1(Message *msg){ /*do something related to type 1*/ }
result processType2(Message *msg){ /*do something related to type 2*/ }

msgProcess[3] = {
  &processType0,
  &processType1,
  &processType2
};

//later
//given an instance of the Message datastructure msg, and that a public field named type is declared and defined, within bound [0,2] 

msgProcess[msg.type]( &msg );

[/edit]

You do not have to, and I think you should not do it.

But you can have empty statements elsewhere:

  if (var == 1) {}

  if (var == 2) {
   var = 1;
  }
  else {}

  for (var = 0; var < 1000000; var++) {}

… are all legal.

So why should the last label in a switch statement be an exception?

As unprinted indicated, sometimes it's useful to the human reader that there is nothing to be done in a certain condition or case. Remember that the code is not just for the machine's benefit. Writing clear code that can be understood months or years later is an important skill. The compiler can optimize the overhead out when it sees there's nothing to be done.

The C language did not always require that extra statement after the default: case. I think it's dumb that it requires it now. You can use just an empty semicolon to fulfill the new requirement. You don't need an empty semicolon if you put a goto label: just before a closing brace, so I don't know why they demand one after default: now.

You can easily have it your way! :)

switch (var) {
  default: { 
  }
}

From me, to you: a completely useless switch-case ;D

[edit]AWOL points out that is is sufficient to simply put a ; after the label. But that, to me, looks more like an error than a definitive 'no op intentional'. A matter of taste/style I guess.[/edit]

OffTopic @AWOL: This was interesting.

Could you not define a function as being a msgProcess and then have an array of such msgProcess(ors) and later index them according to msg type?

Well, yes possibly, but (and it's a massive "but"), this is legacy code. The current code base runs to tens of thousands of 'C' source files, running to many tens of MLOCs. Re-engineering is not an option.

@AWOL I see... Well then, happy casing :)