Reputation: 79299
I am interested if there is any difference from the C or C++ compiler perspective whether I use:
if (value == a) {
...
}
else if (value == b) {
...
}
else if (value == c) {
...
}
versus
switch (value) {
case a:
...
break;
case b:
...
break;
case c:
...
break;
}
It feels to me that there is no difference, just syntactic. Does anyone know more about it?
Thanks, Boda Cydo.
Upvotes: 6
Views: 1053
Reputation: 11
I came to the same problem so I did a few tests, here are some results obtained using gcc version 3.4.6 /centos 4
a.c and c.c use ifs, but c.c takes the variable from command line so the compiler doesn't know the value of "b" at compile time. b.c uses switch
source codes:
a.c
#include <stdint.h>
int main(){
uint32_t i,b=10,c;
for(i=0;i<1000000000;i++){
if(b==1) c=1;
if(b==2) c=1;
if(b==3) c=1;
if(b==4) c=1;
if(b==5) c=1;
if(b==6) c=1;
if(b==7) c=1;
}
}
b.c
#include <stdint.h>
int main(){
uint32_t i,b=10,c;
for(i=0;i<1000000000;i++){
switch(b){
case 1:
c=1;
break;
case 2:
c=1;
break;
case 3:
c=1;
break;
case 4:
c=1;
break;
case 5:
c=1;
break;
case 6:
c=1;
break;
case 7:
c=1;
break;
}
}
}
c.c
#include <stdint.h>
int main(int argc, char **argv){
uint32_t i,b=10,c;
b=atoi(argv[1]);
for(i=0;i<1000000000;i++){
if(b==1) c=1;
if(b==2) c=1;
if(b==3) c=1;
if(b==4) c=1;
if(b==5) c=1;
if(b==6) c=1;
if(b==7) c=1;
}
}
first we compile the programs with no optimization flags:
root@dev2 ~ # gcc a.c -o a;gcc b.c -o b;gcc c.c -o c
root@dev2 ~ # time ./a
real 0m4.871s
user 0m4.866s
sys 0m0.005s
root@dev2 ~ # time ./b
real 0m1.904s
user 0m1.904s
sys 0m0.000s
root@dev2 ~ # time ./c 10
real 0m4.848s
user 0m4.836s
sys 0m0.009s
The results are as I thought, switch is faster than if when no compiler optimization is used.
Now we compile using -O2:
root@dev2 ~ # gcc a.c -o a -O2;gcc b.c -o b -O2;gcc c.c -o c -O2
root@dev2 ~ # time ./a
real 0m0.055s
user 0m0.055s
sys 0m0.000s
root@dev2 ~ # time ./b
real 0m0.537s
user 0m0.535s
sys 0m0.001s
root@dev2 ~ # time ./c 10
real 0m0.056s
user 0m0.055s
sys 0m0.000s
Surprise surprise, both programs (a.c and c.c) using ifs are faster (about 10 times!) than switch.
Upvotes: 1
Reputation: 78903
+1 for David Thomley's answer, since I really find this the most complete.
One important thing is missing though, that is that case
labels must be constant expressions that evaluate at compile time. With if
both sides of the comparison (if you reduce the if
statement to that) are evaluated at run time.
Upvotes: 0
Reputation: 46794
There is a difference - with switch'es, the compiler may optimize the switch to use a lookup table. This may be possible if there are many values which are close enough to each other. For example, this switch:
switch ( integer ) {
case 10:
xxx
break;
case 12:
yyy
break;
case 13
zzz
break;
}
could become (pseudocode):
address = lookup[ integer - 10 ]; // which is prefilled with { case_10, err, err, case_12, case 13 }
goto address;
case_10: xxx; goto err;
case_12: yyy; goto err;
case_13: zzz;
err: //do nothing
Upvotes: 6
Reputation: 57036
There are several differences, according to the Standard.
value
may be evaluated several times in the if
chain, once in the switch
statement. If evaluating value
doesn't have side effects, this is unimportant.if
chain will not allow fallthrough, while the switch
statement will have fallthrough without the break
.if
chain allows general comparison, but the switch
statement only allows comparisons to constant integral expressions.break;
is different. It breaks out of the switch
statement, but any further. If you need to break out of a loop or enclosing switch
statement depending on a condition, you need the if
chain.switch
statement essentially does a goto
to a case
statement or default:
, it will work in different places, the quintessential example being Duff's device. (IIRC, Tom Duff considered it a strong argument in the question of fallthrough, but he wasn't sure on which side.)So, if value
is evaluated without side effects, break;
statements are used consistently and only in the switch
, the comparison is to constant integral values, and it's not used in a funky way, the behavior can be identical. Whether any compilers will use this equivalency is another question.
Upvotes: 3
Reputation: 103485
It's possible, if the select value is an integer (which it must be in C/C++), that the compiler could replace the if's with a jump table.
Upvotes: 0
Reputation: 6895
The case statement may get compiled to a "jump table" which may be faster if there are dozens of cases and you execute this millions of times.
Upvotes: 0
Reputation: 6973
This is going to depend on how the compiler chooses to optimize your code. Code optimization for a compiler is a huge field.
To find the exact answer for your compiler determine how to build assembly code with it and look at the different assembly code that gets written to the file.
This was already done with one compiler and you can see the results here. http://www.eventhelix.com/RealtimeMantra/Basics/CToAssemblyTranslation3.htm
But the short short answers is yes. they will most likely be different.
Upvotes: 1
Reputation: 490018
Yes, there are differences. The cascaded if
s guarantee evaluation of the conditions in order. The switch guarantees only a single evaluation of whatever's used as the switch parameter. Depending on the compiler, the switch will often take (nearly) constant time regardless of the selected branch, whereas the if
cascade pretty much guarantees that the first leg is the fastest, the second second fastest, and so on down to the last being slowest.
Upvotes: 8
Reputation:
A switch should be compiled to a jump with indirect addressing, while a sequence of if statements will be a chain of conditional jumps. First one is constant time; of course, you can put much more general conditions in an if.
Edit: I should mention that I wouldn't be surprised if some smart compilers are able to detect that all conditions in a chain of ifs have a particular simple form and convert to a switch. I don't know if they do, but you can always decompile and check.
Upvotes: 0