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

I am wondering if there is any difference with the perspective of the C or C ++ compiler, do I use:

if (value == a) { ... } else if (value == b) { ... } else if (value == c) { ... } 

against

 switch (value) { case a: ... break; case b: ... break; case c: ... break; } 

It seems to me that there is no difference, just syntactic. Does anyone know more about this?

Thanks, Boda Sido.

+6
c
source share
9 answers

There is a difference - with switch'es, the compiler can optimize the switch to use the lookup table. This may be possible if there are many values ​​that are close enough to each other. For example, this switch:

 switch ( integer ) { case 10: xxx break; case 12: yyy break; case 13 zzz break; } 

can become (pseudo-code):

 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 
+6
source share

Yes, there are differences. Cascading if guarantees the evaluation of conditions in order. The switch guarantees only one estimate of what is used as the switch parameter. Depending on the compiler, the switch often takes a (almost) constant time regardless of the branch selected, while the if cascade largely ensures that the first foot is the fastest, the second second is the fastest and so on to the last slowest.

+8
source share

There are several differences according to the standard.

  • value can be evaluated several times in the if chain once in the switch . If evaluating value has no side effects, it doesn’t matter.
  • The if chain will not let you skip, and the switch will pass without break .
  • The if chain allows for general comparison, but the switch only allows comparisons with constant integral expressions.
  • Using break; is different. It breaks out of the switch , but further. If you need to exit a loop or include a switch depending on the state, you will need an if chain.
  • Since the switch essentially executes the goto in case or default: it will work in different places, a quintessential example of a Duff device . (IIRC, Tom Duff believed this was a strong argument on the issue of failure, but he was not sure which way.)

So, if value is evaluated without side effects, the break; they are used sequentially and only in switch , the comparison is with constant integer values, and it is not used funky, the behavior can be identical. Whether any compilers will use this equivalence is another question.

+3
source share

This will depend on how the compiler wants to optimize your code. Optimizing code for the compiler is a huge field.

To find the exact answer for your compiler, determine how to build assembler code with it and look at the different assembly code that is written to the file.

This has already been done with one compiler, and you can see the results here. http://www.eventhelix.com/RealtimeMantra/Basics/CToAssemblyTranslation3.htm

But the short, short answers are yes. they are likely to be different.

+1
source share

I came to the same problem, so I did some tests, here are some results obtained with gcc version 3.4.6 / centos 4

ac and cc use ifs, but cc takes a variable from the command line, so the compiler does not know the value of "b" at compile time. bc uses a switch

source codes:

ac

 #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; } } 

bc

 #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 programs without optimization flags:

 root@dev2 ~ # gcc ac -oa;gcc bc -ob;gcc cc -oc 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, as I thought, switch faster than if compiler optimization is not used.

Now we compile using -O2:

 root@dev2 ~ # gcc ac -oa -O2;gcc bc -ob -O2;gcc cc -oc -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 

An amazing surprise: both programs (ac and cc), using ifs, are faster (about 10 times!) Than the switch.

+1
source share

The switch must be compiled to jump with indirect addressing, and the sequence of if statements will be a chain of conditional jumps. The first is constant time; Of course, you can put much more general conditions in if.

Edit: I should mention that I won’t be surprised if some intelligent compilers can find that all conditions in the ifs chain have a specific simple form and are converted to a switch. I don’t know if they will do it, but you can always decompile and check.

0
source share

The case statement can be compiled into a "jump table", which can be faster if there are dozens of cases, and you execute these millions of times.

0
source share

Perhaps if the select value is an integer (which should be in C / C ++), then the compiler can replace the if with the jump table.

0
source share

+1 for David Tomley's answer, since I really think this is the most complete.

One important drawback is that case labels must be constant expressions that are evaluated at compile time. With if both sides of the comparison (if you reduce the if to this) are evaluated at runtime.

0
source share

All Articles