What is the point with using {
and }
in a case
statement? Normally, no matter how many lines are there in a case
statement, all of the lines are executed. Is this just a rule regarding older/newer compilers or there is something behind that?
int a = 0; switch (a) { case 0:{ std::cout << "line1\n"; std::cout << "line2\n"; break; } }
and
int a = 0; switch (a) { case 0: std::cout << "line1\n"; std::cout << "line2\n"; break; }
The case statement in SQL returns a value on a specified condition. We can use a Case statement in select queries along with Where, Order By, and Group By clause. It can be used in the Insert statement as well.
CASE must include the following components: WHEN , THEN , and END . ELSE is an optional component. You can make any conditional statement using any conditional operator (like WHERE ) between WHEN and THEN . This includes stringing together multiple conditional statements using AND and OR .
The case statement should include your mission, vision and values statements, and should set out to clearly answer the who, what, and why of your fundraising efforts. The Alaska Food Coalition offers some questions that an effective case statement might seek to answer: - How does this organization help people?
April 1, 2019 by Rajendra Gupta The case statement in SQL returns a value on a specified condition. We can use a Case statement in select queries along with Where, Order By, and Group By clause. It can be used in the Insert statement as well.
In the case of case statements, the condition can be an expression or a value of any datatype. The expression is nothing but a conditional statement returning the appropriate value to be compared. Switch case statements are good for evaluating fixed data types.
It provides an easy way to forward execution to different parts of code based on the value of the expression. There are 3 important keywords which are used in the case statement: case: It is similar to the switch keyword in another programming languages.
The CASE statement goes through conditions and returns a value when the first condition is met (like an if-then-else statement). So, once a condition is true, it will stop reading and return the result. If no conditions are true, it returns the value in the ELSE clause. If there is no ELSE part and no conditions are true, it returns NULL.
The {}
denotes a new block of scope.
Consider the following very contrived example:
switch (a) { case 42: int x = GetSomeValue(); return a * x; case 1337: int x = GetSomeOtherValue(); //ERROR return a * x; }
You will get a compiler error because x
is already defined in the scope.
Separating these to their own sub-scope will eliminate the need to declare x
outside the switch statement.
switch (a) { case 42: { int x = GetSomeValue(); return a * x; } case 1337: { int x = GetSomeOtherValue(); //OK return a * x; } }
Warning:
Declare and initialize a variable inside case
without {}
surrounded is wrong:
#include <iostream> using namespace std; int main() { int b = 3; switch (b) { case 3: int a = 3; //compilation error: "initialization of 'a' skipped by 'case' label" return a * b; case 1: return a * b; } }
TL;DR
The only way you can declare a variable with an intializer or some non-trivial object inside a case is to introduce a block scope using {}
or other control structure that has it's own scope like a loop or if statement.
Gory details
We can see that cases are just labeled statements like the labels used with a goto statement(this is covered in the C++ draft standard section 6.1 Labeled statement) and we can see from section 6.7
paragraph 3 that jumping pass a declaration is not allowed in many cases, including those with an initialization:
It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps87 from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.5).
and provides this example:
void f() { // ... goto lx; // ill-formed: jump into scope of a ly: X a = 1; // ... lx: goto ly; // OK, jump implies destructor // call for a followed by construction // again immediately following label ly }
Note, there are some subtleties here, you are allowed to jump past a scalar declaration that does not have an initialization, for example:
switch( n ) { int x ; //int x = 10 ; case 0: x = 0 ; break; case 1: x = 1 ; break; default: x = 100 ; break ; }
is perfectly valid(live example). Of course if you want to declare the same variable in each case then they will each need their own scope but it works the same way outside of switch statements as well, so that should not be a big surprise.
As for the rationale for not allowing jump past initialization, defect report 467 although covering a slightly different issue provides a reasonable case for automatic variables:
[...]automatic variables, if not explicitly initialized, can have indeterminate (“garbage”) values, including trap representations, [...]
It is probably more interesting to look at the case where you extend a scope within a switch over multiple cases the most famous examples of this is probably Duff's device which would look something like this:
void send( int *to, const int *from, int count) { int n = (count + 7) / 8; switch(count % 8) { case 0: do { *to = *from++; // <- Scope start case 7: *to = *from++; case 6: *to = *from++; case 5: *to = *from++; case 4: *to = *from++; case 3: *to = *from++; case 2: *to = *from++; case 1: *to = *from++; } while(--n > 0); // <- Scope end } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With