In c++ you don't have to put braces {} inside cases in switch statements unless you're declaring a variable.
Consider the following code:
int Lesson82a() {
int test = 1;
switch (test) {
case 1:
{
int i = 1;
cout << i << "\n";
cout << "Inside braces" << "\n";
return 0;
}
case 2:
cout << "2" << "\n";
case 3:
cout << "3" << "\n";
}
return -1;
}
int Lesson82b() {
int test = 1;
switch (test) {
case 1:
{
int i = 1;
cout << i << "\n";
}
cout << "Outside braces" << "\n";
return 0;
case 2:
cout << "2" << "\n";
case 3:
cout << "3" << "\n";
}
return -1;
}
void Lesson82() {
int test = Lesson82a();
cout << test << "\n";
test = Lesson82b();
cout << test;
}
When running Lesson82() the output is as follows:
1
Inside braces
0
1
Outside braces
0
So the result is the same but does it make a difference?
break;
after return even though it's then unreachable?Does it make a difference when it is compiled?
On line 122 here: https://github.com/microsoft/Windows-classic-samples/blob/main/Samples/Win7Samples/begin/LearnWin32/BaseWindow/cpp/main.cpp#L122 i couldn't understand why the return statement is outside the braces.
I tried experimenting but i get the same results in my code regardless of it.
The switch
statement’s cases do not require braces, period.
The purpose of braces is to create a local lexical context — that is, a space where one or more local variables may be created (and consequently given a specific, limited lifetime). In the case of a case
clause in a switch
statement, that lifetime must be limited. Consider:
switch (quux)
{
case 1:
int n = quux / 2;
break;
case 2:
std::cout << "Hello " << n << "!\n";
break;
}
If quux
is 2
, then what is the expected lifetime of n
? Is it even created? When we attempt to print the value of n
, is there even an n
to print?
The answers are no. The targeted switch-case label jumps right over the code that creates it.
In C (before C23), it is a syntactic failure as well: the target of case
labels must be a statement. But int n ...
is a variable declaration.
Sorry, I misread your language tag as C
. But I’ll leave this here since it is worthwhile info for C anyway.
We could move the declaration to before the switch
. Let’s try it:
int n;
switch (quux)
{
case 1:
n = quux / 2;
break;
case 2:
std::cout << "Hello " << n << "!\n";
break;
}
Now when quux
is 2
we jump right over the code that initializes n
with a value. With your compiler warnings turned up, you should definitely see something like:
error: 'n' may be used uninitialized
...which is UB.
These two examples are bad code. (IOW, don’t do that.) They exist solely to demonstrate the problem.
But suppose you have a construct like this:
int n;
switch (quux)
{
case 1:
n = quux / 2;
std::cout << n << "\n";
break;
case 2:
std::cout << "Hello world!\n";
break;
}
Surely life is better, right?
Maybe. But the problems already noted still exist. You cannot declare n
local to where it is used, and in those cases where it is not used, it is uninitialized. I cannot say whether or not this is actually consequential, but it is still something the compiler must think about, so it is.
Aaaand, it is a good idea anyway to make local variables only exist when and for as little time as needed.
The solution: create a local context using {
curly braces }
. This has always been how it works in C and, consequently, C++. It has always been totally valid to do something like:
int main(void)
{
int sum = 0; // x does not exist
{ // (new local context)
int x = 10; // x exists!
while (x) sum += x--; // x exists!
} // (end of scope: x is destroyed)
printf( "%d\n", sum ); // x does not exist
return 0; // x does not exist
}
We can apply this knowledge to use in switch
statements.
switch (quux)
{
case 1:
{
int n = quux / 2;
std::cout << n << "\n";
}
break;
case 2:
std::cout << "Hello world!\n";
break;
}
This is perfectly fine and valid. The case
clauses only contain statements. n
only exists in a local context. Everything is clear and, importantly, easy for the compiler (and us humans) to reason about.
Now, return
and break
statements are attached to very specific brace-enclosed contexts. The return
is attached to a function’s brace-enclosed context. The break
is attached to a switch
(or a loop’s) context. (It is not attached to a case
!)
That means that the position of return
or break
relative to a local brace-enclosed context is irrelevant. Both are valid:
switch (quux) | switch (quux)
{ | {
case 1: | case 1:
{ | {
int n = quux / 2; | int n = quux / 2;
std::cout << n << "\n"; | std::cout << n << "\n";
break; | }
} | break;
case 2: | case 2:
std::cout << "Hello world!\n"; | std::cout << "Hello world!\n";
break; | break;
} | }
In both of these cases the local context is properly terminated before the break
jumps control to the end of the entire switch
statement.
The list of statements following a case
label are like any other list of statements: they may contain brace-enclosed local contexts in any fashion you wish.
switch (quux)
{
case 1:
{
std::cout << "inside\n";
}
std::cout << "outside\n";
{
std::cout << "inside again, lol\n";
}
break;
}
Just... try to write readable code. This leads us to the final bit:
Brace-enclosed spaces are easily elided by the compiler when they serve no purpose. So using braces for stylistic reasons is fine:
switch (quux)
{
case 1:
{
int n = quux / 2;
std::cout << n << "\n";
break;
}
case 2:
{
std::cout << "Hello world!\n";
break;
}
}