在使用if,else if,else if,...和using switch(){case A:... case B:...}之间,C和C++有什么区别吗?

问题描述:

我感兴趣,如果有从C或任何区别C++编译器的角度来看,我是否使用:在使用if,else if,else if,...和using switch(){case A:... case B:...}之间,C和C++有什么区别吗?

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

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

这种感觉对我来说,没有什么区别,只是语法。有人知道更多关于它吗?

谢谢,Boda Cydo。

有一个区别 - 与switch'es,编译器可能优化交换机使用查找表。如果有很多数值足够接近,这可能是可能的。例如,此开关:

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

可能成为(伪):

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 
+0

对于'if's,在某些情况下,编译器可以优化'if'树来使用查找表。对于目前的编译器来说,这种情况的可能性要小得多,但并没有超出标准所说的。 – 2010-07-30 17:33:26

一个开关应该被编译为一个间接寻址的跳转,而if语句的序列将是一个有条件的跳转链。第一个是不变的时间;当然,你可以在一个if中放置更多的一般条件。

编辑:我应该提到,如果一些智能编译器能够检测到ifs链中的所有条件都具有特定的简单形式并转换为开关,我不会感到惊讶。我不知道他们是否会这样做,但是您可以随时反编译并检查。

是的,有差异。级联的if保证对条件的评估顺序。该开关仅保证对用作开关参数的任何一种评估。根据编译器的不同,交换机通常需要(几乎)恒定的时间,而不管选择的分支是什么,而if级联几乎可以保证第一条路是最快的,第二路是最快的,等等,最后是最慢的。

+2

这不是很简单。如果条件没有副作用(如OP所示),编译器可以轻松地重新排序if/else。例如,[gcc](http://gcc.gnu.org/onlinedocs/gcc-4.5.0/gcc/Optimize-Options.html#Optimize-Options)可以通过选项如'-freorder-blocks'和'-fguess分支 - probability'。在某些情况下,编译器也可以从级联中生成跳转表。最后,如果值太稀疏,switch语句不会产生跳转表。 – 2010-07-29 17:50:02

这将取决于编译器如何选择优化代码。编译器的代码优化是一个巨大的领域。

要找到编译器的确切答案,请确定如何使用它构建汇编代码,并查看写入该文件的不同汇编代码。

这已经用一个编译器完成了,你可以在这里看到结果。 http://www.eventhelix.com/RealtimeMantra/Basics/CToAssemblyTranslation3.htm

但简短的答案是肯定的。他们很可能会有所不同。

case语句可以被编译为“跳表”,这可能会更快,如果有数十例和你执行这数百万次。

如果选择值是一个整数(它必须在C/C++中),那么编译器可以用跳转表替换if是可能的。

根据标准,有几处不同。

  1. value可以在if链进行评估几次,一次是在switch声明。如果评估value没有副作用,这是不重要的。
  2. if链不会允许下通,而switch语句将有下通没有break
  3. if链允许比较一般,但switch语句只允许进行对比,以整型常量表达式。
  4. 使用的break;是不同的。它突破了switch声明,但任何进一步的。如果你需要跳出循环或封闭switch语句根据条件的,你需要的if链。
  5. 由于switch声明本质上是gotocase声明或default:,它将在不同的地方工作,典型示例是Duff's device。 (IIRC,汤姆·达夫认为它的下通的问题,一个有力的论据,但他不知道在哪一方。)

所以,如果value是无副作用的评估,break;声明一致,仅使用在switch,比较是恒定积分值,并且它不是在一个时髦的方式使用,则该行为可以是相同的。是否有编译器会使用这种等同性是另一个问题。

+1 David Thomley的回答,因为我真的觉得这是最完整的。

虽然缺少一件重要的事情,那就是case标签必须是在编译时评估的常量表达式。与if比较的两侧(如果您减少if语句)在运行时进行评估。

我来到了同样的问题,所以我做了一些测试,这里有一些结果使用gcc版本3.4.6/CentOS的4

AC和CC使用IFS获得,但CC需要从命令行,以便变量编译器在编译时不知道“b”的值。 b.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; 
    } 
} 

首先我们编译的程序没有优化标志:

[email protected] ~ # gcc a.c -o a;gcc b.c -o b;gcc c.c -o c 
[email protected] ~ # time ./a 

real 0m4.871s 
user 0m4.866s 
sys  0m0.005s 
[email protected] ~ # time ./b 

real 0m1.904s 
user 0m1.904s 
sys  0m0.000s 
[email protected] ~ # time ./c 10 

real 0m4.848s 
user 0m4.836s 
sys  0m0.009s 

结果如我所料,开关比没有使用编译器优化时更快。

现在我们编译使用-02:

[email protected] ~ # gcc a.c -o a -O2;gcc b.c -o b -O2;gcc c.c -o c -O2 
[email protected] ~ # time ./a 

real 0m0.055s 
user 0m0.055s 
sys  0m0.000s 
[email protected] ~ # time ./b 

real 0m0.537s 
user 0m0.535s 
sys  0m0.001s 
[email protected] ~ # time ./c 10 

real 0m0.056s 
user 0m0.055s 
sys  0m0.000s 

惊喜惊喜,采用IFS两个程序(交流转换器和C.C)快于开关(约10倍!)。