I wrote the following code:
int i = 0;
switch(i++)
{
case 0:
cout << 0;
case 1:
cout << 1;
}
cout << "\n" << i;
The output of the code was like this:
01
1
Can anyone please explain the first line of output? Why are 0 and 1 both being printed?
First, the expression i++ (post-increment operator) evaluates to 0 (even though it sets the value of i to 1). So inside the switch, the case 0: branch is selected.
Then, because there is no break after your case 0:, the program continues with executing the code in the case 1: label.
Summing it up, you have: 0 from the first switch branch, 1 from the second branch, and another 1 because that's the final value of i.
Because you need to add a break after each case, which prevents execution of the following statements. E.g.
switch(i++)
{
case 0:
cout<<0;
break;
case 1:
cout<<1;
break;
}
Admittedly, the second break is superfluous but I put it there just for the sake of consistency
you need to put "break;" at the end of each case.
switch is a strange construct. It comes from C, and Java and C# adopted it too, so it is not considered totally "non-OO".
switch on state which changes is a valid OO concept, but often is used for switching based on type.
In particular the compiler usually creates a "jump" table which means it is O(1) what block of code gets called, unlike a nested "if" statement. You may have multiple values (not including default) jump to the same point, thus code blocks "run into" each other unless you explicitly insert a "break" statement.
This is how it was done in C and has been retained for C++.
With regards to the value in the switch, it must be a numeric value but does not have to be a constant. In your case i++ evaluates to 0 but increments i to 1. This is well-defined behaviour and there is no issues with sequence points here.
Related
My Q is why to use switch statement and the conditional operator when we have the (if else && else if)
Example 1 :
unsigned short int any_number ;
any_number = ((15>0)? 10 : 5);//using here the conditional operator
if(15>0)//using if & else
any_number=10;
else
any_number=5;
Example 2 :
unsigned short int my_score;
std::cout << "what score you expect you got at the exam";
cin >> my_score;
switch(my_score)
{
case 90:
std::cout<<"awesome keep the good work"; break;
case 80 :
std::cout<<"study harder next time"; break ;
case 20:
std::cout << "quit school"; break;
}
if(my_score==90)
std::cout<<"awesome keep the good work";
else if (my_score==80)
std::cout<<"study harder next time";
else if (my_score==20)
std::cout << "quit school";
other than its costs less lines using swith and conditional operators i dont find them useful at all i like more the (if else) more it gives us more space can any one till me the diffrence if there is one ?
There are many reasons why we need switch statement, it is faster and cleaner(my opinion), but there is another reason: if you switch over an enum variable, and if you forgot to handle some enum values, the compiler can catch it for you.
c++ warning: enumeration value not handled in switch [-Wswitch]
main reason is readability
a long sequence of if elses is sometimes harder to read and maintain than a switch statement.
BTW the performance difference will surely disappear in production code created by a modern compiler.
The ?: construct allows you to do thing not expressable in ifs
cout << (j>42?"a":"b")
for example
Your main concern is code readability and how error-prone it is.
For example, when not used with switch, case and breaks (!), it's probably safer to go for if-else.
In C++ is it better to use switch and case statements or to use if statements?
Personally I find the answers there as great as they are simple.
switch case is faster!
for this point, you can use those two structures to write two functionally equivalent codes, and then compare the compiled assembly code.
details you can refer to this: Efficiency analysis of switch and if else
Before you down-vote or start saying that gotoing is evil and obsolete, please read the justification of why it is viable in this case. Before you mark it as duplicate, please read the full question.
I was reading about virtual machine interpreters, when I stumbled across computed gotos . Apparently they allow significant performance improvement of certain pieces of code. The most known example is the main VM interpreter loop.
Consider a (very) simple VM like this:
#include <iostream>
enum class Opcode
{
HALT,
INC,
DEC,
BIT_LEFT,
BIT_RIGHT,
RET
};
int main()
{
Opcode program[] = { // an example program that returns 10
Opcode::INC,
Opcode::BIT_LEFT,
Opcode::BIT_LEFT,
Opcode::BIT_LEFT,
Opcode::INC,
Opcode::INC,
Opcode::RET
};
int result = 0;
for (Opcode instruction : program)
{
switch (instruction)
{
case Opcode::HALT:
break;
case Opcode::INC:
++result;
break;
case Opcode::DEC:
--result;
break;
case Opcode::BIT_LEFT:
result <<= 1;
break;
case Opcode::BIT_RIGHT:
result >>= 1;
break;
case Opcode::RET:
std::cout << result;
return 0;
}
}
}
All this VM can do is a few simple operations on one number of type int and print it. In spite of its doubtable usefullness, it illustrates the subject nonetheless.
The critical part of the VM is obviously the switch statement in the for loop. Its performance is determined by many factors, of which the most inportant ones are most certainly branch prediction and the action of jumping to the appropriate point of execution (the case labels).
There is room for optimization here. In order to speed up the execution of this loop, one might use, so called, computed gotos.
Computed Gotos
Computed gotos are a construct well known to Fortran programmers and those using a certain (non-standard) GCC extension. I do not endorse the use of any non-standard, implementation-defined, and (obviously) undefined behavior. However to illustrate the concept in question, I will use the syntax of the mentioned GCC extension.
In standard C++ we are allowed to define labels that can later be jumped to by a goto statement:
goto some_label;
some_label:
do_something();
Doing this isn't considered good code (and for a good reason!). Although there are good arguments against using goto (of which most are related to code maintainability) there is an application for this abominated feature. It is the improvement of performance.
Using a goto statement can be faster than a function invocation. This is because the amount of "paperwork", like setting up the stack and returning a value, that has to be done when invoking a function. Meanwhile a goto can sometimes be converted into a single jmp assembly instruction.
To exploit the full potential of goto an extension to the GCC compiler was made that allows goto to be more dynamic. That is, the label to jump to can be determined at run-time.
This extension allows one to obtain a label pointer, similar to a function pointer and gotoing to it:
void* label_ptr = &&some_label;
goto (*label_ptr);
some_label:
do_something();
This is an interesting concept that allows us to further enhance our simple VM. Instead of using a switch statement we will use an array of label pointers (a so called jump table) and than goto to the appropriate one (the opcode will be used to index the array):
// [Courtesy of Eli Bendersky][4]
// This code is licensed with the [Unlicense][5]
int interp_cgoto(unsigned char* code, int initval) {
/* The indices of labels in the dispatch_table are the relevant opcodes
*/
static void* dispatch_table[] = {
&&do_halt, &&do_inc, &&do_dec, &&do_mul2,
&&do_div2, &&do_add7, &&do_neg};
#define DISPATCH() goto *dispatch_table[code[pc++]]
int pc = 0;
int val = initval;
DISPATCH();
while (1) {
do_halt:
return val;
do_inc:
val++;
DISPATCH();
do_dec:
val--;
DISPATCH();
do_mul2:
val *= 2;
DISPATCH();
do_div2:
val /= 2;
DISPATCH();
do_add7:
val += 7;
DISPATCH();
do_neg:
val = -val;
DISPATCH();
}
}
This version is about 25% faster than the one that uses a switch (the one on the linked blog post, not the one above). This is because there is only one jump performed after each operation, instead of two.
Control flow with switch:
For example, if we wanted to execute Opcode::FOO and then Opcode::SOMETHING, it would look like this:
As you can see, there are two jumps being performed after an instruction is executed. The first one is back to the switch code and the second is to the actual instruction.
In contrary, if we would go with an array of label pointers (as a reminder, they are non-standard), we would have only one jump:
It is worthwhile to note that in addition to saving cycles by doing less operations, we also enhance the quality of branch prediction by eliminating the additional jump.
Now, we know that by using an array of label pointers instead of a switch we can improve the performance of our VM significantly (by about 20%). I figured that maybe this could have some other applications too.
I came to the conclusion that this technique could be used in any program that has a loop in which it sequentially indirectly dispatches some logic. A simple example of this (apart from the VM) could be invoking a virtual method on every element of a container of polymorphic objects:
std::vector<Base*> objects;
objects = get_objects();
for (auto object : objects)
{
object->foo();
}
Now, this has much more applications.
There is one problem though: There is nothing such as label pointers in standard C++. As such, the question is: Is there a way to simulate the behaviour of computed gotos in standard C++ that can match them in performance?.
Edit 1:
There is yet another down side to using the switch. I was reminded of it by user1937198. It is bound checking. In short, it checks if the value of the variable inside of the switch matches any of the cases. It adds redundant branching (this check is mandated by the standard).
Edit 2:
In response to cmaster, I will clarify what is my idea on reducing overhead of virtual function calls. A dirty approach to this would be to have an id in each derived instance representing its type, that would be used to index the jump table (label pointer array). The problem is that:
There are no jump tables is standard C++
It would require as to modify all jump tables when a new derived class is added.
I would be thankful, if someone came up with some type of template magic (or a macro as a last resort), that would allow to write it to be more clean, extensible and automated, like this:
On a recent versions of MSVC, the key is to give the optimizer the hints it needs so that it can tell that just indexing into the jump table is a safe transform. There are two constraints on the original code that prevent this, and thus make optimising to the code generated by the computed label code an invalid transform.
Firstly in the original code, if the program counter overflows the program, then the loop exits. In the computed label code, undefined behavior (dereferencing an out of range index) is invoked. Thus the compiler has to insert a check for this, causing it to generate a basic block for the loop header rather than inlining that in each switch block.
Secondly in the original code, the default case is not handled. Whilst the switch covers all enum values, and thus it is undefined behavior for no branches to match, the msvc optimiser is not intelligent enough to exploit this, so generates a default case that does nothing. Checking this default case requires a conditional as it handles a large range of values. The computed goto code invokes undefined behavior in this case as well.
The solution to the first issue is simple. Don't use a c++ range for loop, use a while loop or a for loop with no condition. The solution for the second unfortunatly requires platform specific code to tell the optimizer the default is undefined behavior in the form of _assume(0), but something analogous is present in most compilers (__builtin_unreachable() in clang and gcc), and can be conditionally compiled to nothing when no equivalent is present without any correctness issues.
So the result of this is:
#include <iostream>
enum class Opcode
{
HALT,
INC,
DEC,
BIT_LEFT,
BIT_RIGHT,
RET
};
int run(Opcode* program) {
int result = 0;
for (int i = 0; true;i++)
{
auto instruction = program[i];
switch (instruction)
{
case Opcode::HALT:
break;
case Opcode::INC:
++result;
break;
case Opcode::DEC:
--result;
break;
case Opcode::BIT_LEFT:
result <<= 1;
break;
case Opcode::BIT_RIGHT:
result >>= 1;
break;
case Opcode::RET:
std::cout << result;
return 0;
default:
__assume(0);
}
}
}
The generated assembly can be verified on godbolt
I've got a problem where I want to do one of three things...
if the value of x is 1-5 (inclusive) do A, if x is between 6-13 (inclusive) do B, and if x is between 14-16 do C.
I figured the switch case would be ok, although I guess I could use a plain IF / ELSE IF, however, as I coded it, I can't help but think there is a more elegant way of stating this USING the switch/case (just in case I encounter a similar need that has more then three options).
here is what I have:
switch ( x ) {
case 1:case 2:case 3:case 4:case 5:
// DO A
break;
case 6:case 7:case 8:case 9:case 10:case 11:case 12:case 13:
// DO B
break;
case 14:case 15:case 16:
// DO C
break;
}
is there a way in the case to specify "between" (inclusive or exclusive)?
thanks
Nope. Switch statement are designed to work with single, constant values. Unless the comparison is such that the value can be modified to conform to that rule, the only options are what you have written already OR using if/else if/else, AFAIK. In most cases, the latter is cleaner than a bunch of hard coded case statements IMO.
While I am reading in a code, I found that the loop for was used with just two arguments (the one in the middle is absent). When the program is executed, the loop for is infinite. Here is a minimal working environment. Could anyone tell what is wrong in the code?
// Example program
#include <iostream>
using namespace std;
int main()
{
for (int i = 0; ; i = (i+1)%2)
{
cout << i << endl;
}
}
when you have
for (statement 1;statement 2;statement 3){}
statement 1: performs at entry to the for loop
statement 2: is checked before every new iteration, if it evaluates as 0/false it doesn't continue
statement 3: is performed at end of every iteration regardless.
if you leave statement 2 empty it default to true/1 and so every time it loops it will evaluate as continuing and so will be an infinite loop
There's nothing wrong with the code, it's doing exactly what you told it to do.
The second section of the if statement is the continuation condition which, if omitted, defaults to true.
In fact, you can leave out any combination of the loop initialisation, continuation condition and post-iteration sections and they will default to, respectively:
no initialisation.
continue forever (in the absence of control flow statements like break).
no post-iteration actions.
which is why:
for (;;)
is a perfectly valid infinite loop.
This is explained in the C standard. ยง6.8.5.3:
1 The statement
for ( clause-1 ; expression-2 ; expression-3 ) statement
behaves as follows: The expression expression-2 is the controlling expression that is evaluated before each execution of the loop body. [..]
2 Both clause-1 and expression-3 can be omitted. An omitted
expression-2 is replaced by a nonzero constant.
That essentially means that it will repeat forever.
A further explanation continues in a footnote (which is considered non-normative):
158) Thus, clause-1 specifies initialization for the loop, possibly
declaring one or more variables for use in the loop; the controlling
expression, expression-2, specifies an evaluation made before each
iteration, such that execution of the loop continues until the
expression compares equal to 0; and expression-3 specifies an
operation (such as incrementing) that is performed after each
iteration.
There is nothing wrong with the code. This allows infinite counting (to an int's limit that is) until an internal condition stops it. None of the three parts of a for loop are necessary, thus any of the below are valid.
for(;;); // Yes, this will never stop
for(int x = 0;;){
}
for(int x = 0; x < 10; ++x);
for(; someCondition != true;){}
And so on, all parts are optional, even the body.
A reason this might be used would be that if one thing is done with the data, I need to stop, but if another thing, I want to do something with it. However, at the same time, I need to know how many times it's happened. You'll use it without all the parameters eventually, but for now, just understand that to have a valid for loop, all you have to have is the top line in my code snippet above.
The syntax for a for loop in C++ is:
for ( init; condition; increment )
{
//statement(s) to be executed while the condition is true
}
See here for more details: http://www.tutorialspoint.com/cplusplus/cpp_for_loop.htm
Your prgram missed the condition statement. Therefore, the for loop repeated forever.
This question already has answers here:
How do I select a range of values in a switch statement?
(18 answers)
Closed 9 years ago.
Am I able to add sets instead of numbers to "switch" statement? Like:
switch(number)
{
case 1<50: //if number is between 1 and 50
{
blah;
break;
}
case 50<100: //if number is between 50 and 100
{
blah;
break;
}
and so on.
(Edit following comments below, acknowledgement given to user syam)
No. In C++ you can only switch on things that reduce to an integer. You'll need to build a function that computes integral results for 1 < 50 and 50 < 100 etc. and use switch(thatFunction(...)).
Or, if you don't need the follow-though idiom that a switch gives you (by the looks of your example, you don't), just use if, else if, else.
Extract from below comments:
6.4.2-2 [stmt.switch] The condition shall be of integral type, enumeration type, or of a class type for which a single non-explicit conversion function to integral or enumeration type exists [...] the constant-expression shall be a converted constant expression (5.19) of the promoted type of the switch condition
1 < 50 is a boolean expression that gets a compile-time value of true, and thus becomes 1 in an integer context. So you end up with two identical cases in your switch. Compile with high warning level - your compiler will surely complain.
Sadly not. You can use fall-through for a small set of discrete values:
case 1:
case 2:
blah;
break;
but for large ranges the only sensible option is if...else.
For me, this works on my g++ (GCC) 4.7.2 20121109
#include <iostream>
using namespace std;
int main() {
switch(6) {
case 1 ... 5:
cout << "Between 1 and 5" << endl;
break;
case 6 ... 10:
cout << "Between 6 and 10" << endl;
break;
}
}
Thanks for stating in the comments that it's GCC's extenstion
Conditionals are not permitted as case statements, so your option is to use if / else statements.
You can't do that in C++. case switches must be a constant that can be converted to an int.
This is nicely discussed here.
A switch statement is useful when you have to use a single variable across many possible conditions. A switch statement works faster than an if-else block by using a jump table. It requires constant integers when it makes the table. The reason expressions that dont evaluate to a fixed value are not allowed is to save from ambiguity.
case 1+a;
break;
case 5;
break;
Now what if a is 4. That will cause issues. If it doesnt use the jump table it wont be much useful than an if-else block