bodacydo
bodacydo

Reputation: 79299

Is there any difference in C and C++ between using if, else if, else if, ... and using switch () { case A: ... case B: ... }?

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

Answers (9)

Cosmin
Cosmin

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

Jens Gustedt
Jens Gustedt

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

adamk
adamk

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

David Thornley
David Thornley

Reputation: 57036

There are several differences, according to the Standard.

  1. The 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.
  2. The if chain will not allow fallthrough, while the switch statement will have fallthrough without the break.
  3. The if chain allows general comparison, but the switch statement only allows comparisons to constant integral expressions.
  4. The use of 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.
  5. Since a 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

James Curran
James Curran

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

rep_movsd
rep_movsd

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

madmik3
madmik3

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

Jerry Coffin
Jerry Coffin

Reputation: 490018

Yes, there are differences. The cascaded ifs 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

anon
anon

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

Related Questions