The introduction to the switch statement in the Getting Started book is relatively simple, so I also have a lot of misunderstandings. I wrote the following short switch statement to solve the problem. I believe it will be helpful to many of my friends and I will also add some related knowledge.
First, a question is thrown out. For details, refer to the following procedure:
// The original code is from the C Language Reference Manual (5th)
// Some changes were made to express my intention
Switch (X)
{
Default:
If (prime (x ))
{
Case 2: Case 3: Case 5: Case 7:
Process_prime (X );
}
Else
{
Case 4: Case 6: Case 8: Case 9: Case 10:
Process_composite (X );
}
}
Can you tell us how it works?
The format of the switch statement is:
Switch statement
Where, the condition type can be integer, enumeration, or class type (but the class must have a single conversion to integer type or (it can be a character type, but it cannot be a floating point type, string type, pointer type, etc.), the statement part does not have to be a compound statement. Therefore, switch ("123" [2] + (INT) 3.1); is a valid switch statement, switch (j) case 5: I ++; it is also a valid switch statement. If the switch statement is a non-composite statement, the variable scope defined in the switch statement is equivalent to {} added to the statement {}. For example, int I = 3; Switch (I) int I = 4;, equivalent to int I = 3; Switch (I) {int I = 4 ;}, therefore, this does not cause repeated definitions in the same local domain.
If the condition is of the class type, a user-defined type conversion operator is required in the class to overload the function. The following code is used:
# Include
Using namespace STD;
Class ctest
{
Public:
Operator int () {cout <"int" <
Operator char () {cout <"int" <(data );}
Ctest (int I): Data (I ){}
Ctest (char C): Data (c ){}
PRIVATE:
Int data;
};
Int main ()
{
Ctest x1 (3 );
Ctest X2 ('5 ');
Switch (X1)
{
Case '5': break;
Case 3: break;
}
Return 0;
}
In VC ++ 6, the compiler reports the following error message:
Error c2450: Switch expression of type 'class ctest' is illegal ambiguous user-defined-Conversion
The compiler cannot determine which type conversion function to call because two of the type conversion functions are integer.
The condition can also be initialized like int I = 3, and the result is the value of I. Its scope starts from the Declaration and ends with the switch statement. It can be understood that {} is added outside the switch {}. Multiple initialization methods such as int I = 3, j = 4 are not a condition in the C ++ standard.
Statement, multiple case labels and one default label can appear, and their appearance order is random. A case or default label corresponds to the switch statement closest to its upper layer, for example:
Switch (I)
{
Case 1:
Case 2:
If (A> 5)
{
Case 3:
Case 4:
B = 4;
Switch (j)
{
Case 5:
Default :;
}
Default :;
}
}
, Case 3:, case 4:, and the last default:, belong to the outer switch, although they are in the IF statement. Note that in the code above,} is the last label followed by at least one statement. Therefore, if there is no content, at least one empty statement should be used as the end.
The case label is a constant expression of the integer type, so int I = 3; Switch (I) {Case 3 :;} is valid while int I = 3; Switch (3) {case I:;} is invalid because I of case I: is not a static expression. If you replace int I = 3; with const int I = 3; then the latter is valid in C ++, but it is still invalid in C. The reason is that C and C ++ have different processing methods for const. In C, the quantity limited by const cannot be modified directly, but it is not a constant expression; in C ++, if the value of const can be determined during compilation, it can appear where constant expressions must be used.
The case labels of the same switch cannot be repeated. Note that there is an upper limit for the implementation of case labels: The c89 standard requires at least 257 labels, which ensures that ASCII is listed by the switch.
Although the case label is a constant expression, it seems that it is not very simple (for example, compared with the select case of VB), this design can ensure higher efficiency, efficiency is the most important factor in C and C ++. Because the value of the Case label is an integer type that can be determined during compilation and cannot be duplicated, the compiler can optimize it. For example, the following code:
Switch (B)
{
Case 0 :...
Case 1 :...
...
Case 255 :...
}
Not translated
If (B = 0)
...
Else if (B = 1)
...
Else if (B = 255)
...
In this case, when B is 255, the execution will be slowest. If the compiler optimizes 256 numbers, it can generate such code based on the frequency and importance of comparison:
If (B <1, 128)
{
If (B <64)
...
}
Else
{
If (B <1, 192)
...
}
This half-fold method reduces the number of more experienced steps and improves the execution efficiency of switch statements in a multi-tier loop. Of course, the premise is that you need to know when it is better to use it, such as parsing command line parameters. If the conditions are relatively complex, use if else instead of switch.
A common misunderstanding of switch is to understand switch as if and put:
Switch (B)
{
Case 1:...; break;
Case 2:...; break;
Case 3:...; break;
Default:...; break;
}
It is actually:
If (B = 1)
{
...
}
Else if (B = 2)
{
...
}
Else if (B = 3)
{
...
}
Else
{
...
}
Yes, the execution of the above two segments is indeed equivalent,:
Switch (B)
{
Case 1 :...
Case 2 :...
Case 3 :...
Default :...
}
It is not equivalent:
If (B = 1)
{
...
}
Else if (B = 2)
{
...
}
Else if (B = 3)
{
...
}
Else
{
...
} // If the code is generated in this way, not only does the break Branch need to generate one more Goto, but the comparison of condition values is also scattered in multiple places, which is inefficient!
If there is no break after each label, the switch code will be executed. The switch code above should be understood:
// Pseudocode
{
If (B = 1) goto case 1;
Else if (B = 2) goto case 2;
Else if (B = 3) goto case 3;
Else goto default;
Goto end_of_switch // if no default exists
{
Case 1 :...
Case 2 :...
Case 3 :...
Default :...
End_of_switch:
}
}
The break in the outermost layer of the switch statement is equivalent to the Goto end_of_switch of pseudo code. This explains the code execution sequence after each label, and then understands the specific principle of whereabouts. It also explains why the order of numbers is random.
Switch execution method: the switch evaluates the condition, and then compares all case labels (if any) (the comparison sequence may be optimized, or the compared condition value is always placed in a register, and assembly commands such as CMP are used to improve efficiency), and the matching value jumps to the specified label like Goto. If it fails, it will go to goto default. If the program does not write default, it will jump to the next position of the switch statement. The case and default labels are similar to common labels and do not set else if to determine the conditions when they appear. Therefore, the case label and default label do not affect the whereabouts. Comparing and transferring the code to the corresponding label can be understood as completely generated by the switch (condition) statement.
Back to the question at the beginning of the article, we will convert it into the corresponding pseudo code:
{
If (x = 2) goto case 2; // The actual assembly code may be optimized.
Else if (x = 3) goto case 3;
Else if (x = 5) goto case 5;
Else if (x = 7) goto case 7;
Else if (x = 4) goto case 4;
Else if (x = 6) goto case 6;
Else if (x = 8) goto case 8;
Else if (x = 9) goto case 9;
Else if (x = 10) goto case 10;
Else goto default;
Goto end_of_switch; // This sentence is useless. It is unnecessary to generate a default statement.
{
Default:
If (! Prime (x) goto part_of_else; // For ease of understanding, the IF statement is also converted
Case 2:
Case 3:
Case 5:
Case 7:
Process_prime (X );
Goto end_of_if;
Part_of_else:
Case 4:
Case 6:
Case 8:
Case 9:
Case 10:
Process_composite (X );
End_of_if :;
End_of_switch :;
}
}
The if part of the program uses the prime () function to determine whether the X value is a prime number. If so, process_prime () is called; otherwise process_composite () is called (). However, the other factor is that in most cases, the number to be judged is less than or equal to 10. If you call prime () for the case of <= 10, it will undoubtedly reduce the efficiency. Therefore, the switch will first judge the situation within the range of 2 to 10, and jump to the corresponding position for processing. If it is not in the range of 2 to 10, it will jump to the default, and then call prime to judge.
When switch (x) int I = 3;
The final issue to be emphasized is that GOTO in C ++ cannot skip variable definitions from the past to the next. Therefore, it is best to include variable definition statements in compound statements.
See the following code:
Switch (X)
{
Case 0: F0 (); break;
Case 1: ctest I (3); F1 (); break;
Default: fdef ();
}
Its pseudo code is:
{
If (x = 0) goto case 0;
Else if (x = 1) goto case 1;
Else goto default;
{
Case 0:
F0 (); goto end_of_switch;
Case 1:
Ctest I (3 );
F1 ();
Goto end_of_switch;
Default:
Fdef ();
End_of_switch:
Ctest ::~ Ctest ();
}
}
When X is 0 or 1, there is no problem. The problem is that when it is switched to default, it is equivalent to skipping the I structure directly from the outer layer, and then after the default code is executed, also execute the I destructor. Changed:
Switch (X)
{
Case 0: F0 (); break;
Case 1: {ctest I (3); F1 (); break ;}
Default: fdef ();
}
Then the I scope is limited to {}, and there will no longer be issues of structure analysis without construction.