Trying to understand the compiler error

Compiling the below code (only for demo purposes)

#define STATE1 1
#define STATE2 2

void setup()
{
}

void loop()
{
  char value = 33;
  switch (value)
  {
    case STATE1:
      char x = Serial.read();
      break;
    case STATE2:
      char x = Serial.read();
      break;
  }
}

Results in the below compiler error.

C:\Users\sterretje\Documents\Arduino\sketch_may14e\sketch_may14e.ino: In function 'void loop()':
sketch_may14e:2: error: jump to case label [-fpermissive]
 #define STATE2 2
                ^
C:\Users\sterretje\Documents\Arduino\sketch_may14e\sketch_may14e.ino:15:10: note: in expansion of macro 'STATE2'
     case STATE2:
          ^
sketch_may14e:13: error: crosses initialization of 'char x'
       char x = Serial.read();
            ^
sketch_may14e:16: error: redeclaration of 'char x'
       char x = Serial.read();
            ^
sketch_may14e:13: error: 'char x' previously declared here
       char x = Serial.read();
            ^
exit status 1
jump to case label [-fpermissive]

And the line that is 'highlighted' in the editor is the second #define

I know how to solve it, but why does seem to break its neck on a #define and thinks that there are jumps?

The solution is to either give char x a broader scope or to use curlies around the case block (something I've never done). Using char x1 and char x2 in the respective cases does not solve the issue.

There are problems when you declare a variable inside switch/case. I believe that it works if you put braces round the code for each case, which is not normally necessary.

The cases inside a switch case are not separate blocks: it's a single block with (in effect) a set of GOTO labels. This is why you need the break statements - without them, the execution will "fall though", which is often a useful technique for various things.

Thanks people.

It indeed works of you use curly braces (one of the options I mentioned). I also know about the use of break and 'fall through' :wink:

If the switch is indeed one big block (I did not know that one :wink: ), it explains why I can't declare the same variable. But the error stays if I declare 2 variables.

The biggest confusion is that it complains about a '#define' that is fully valid. Took me 30 minutes yesterday to figure out how to solve it so it would compile.

sterretje:
Using char x1 and char x2 in the respective cases does not solve the issue.
...
But the error stays if I declare 2 variables.

You are getting the error "crosses initialization of 'char x'" because like what Paul said, a switch is a single scope.

So a variable you declare in one case can be used in another. This is a problem because unless execution first enters the case initializing the variable and falls through to a case using the variable (can see it as its the same scope) you'll be using the value which has not been initialized.

In the case of the code which skips the initialization: C++ has a paradigm which is RAII, or "resource acquisition is initialization". So not only is the variable not initialized, it can be considered that it doesn't even exist in the stack. If C++ allowed it, it would be analogous to using a pointer to some random location.

The curly bracket fix works as it defines a 'nested scope', and is a single statement (compound statement), and the variables lifetime exists only within that scope.

Also, (a little off topic) you can declare a variable in the switch condition.

  switch(int i = random(10)){
    case 1:
      i = 4;
      break;
      
    case 2:
      Serial.print(i);
      break;
  }