在使用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
一个开关应该被编译为一个间接寻址的跳转,而if语句的序列将是一个有条件的跳转链。第一个是不变的时间;当然,你可以在一个if中放置更多的一般条件。
编辑:我应该提到,如果一些智能编译器能够检测到ifs链中的所有条件都具有特定的简单形式并转换为开关,我不会感到惊讶。我不知道他们是否会这样做,但是您可以随时反编译并检查。
是的,有差异。级联的if
保证对条件的评估顺序。该开关仅保证对用作开关参数的任何一种评估。根据编译器的不同,交换机通常需要(几乎)恒定的时间,而不管选择的分支是什么,而if
级联几乎可以保证第一条路是最快的,第二路是最快的,等等,最后是最慢的。
这不是很简单。如果条件没有副作用(如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是可能的。
根据标准,有几处不同。
- 的
value
可以在if
链进行评估几次,一次是在switch
声明。如果评估value
没有副作用,这是不重要的。 - 的
if
链不会允许下通,而switch
语句将有下通没有break
。 - 的
if
链允许比较一般,但switch
语句只允许进行对比,以整型常量表达式。 - 使用的
break;
是不同的。它突破了switch
声明,但任何进一步的。如果你需要跳出循环或封闭switch
语句根据条件的,你需要的if
链。 - 由于
switch
声明本质上是goto
到case
声明或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倍!)。
对于'if's,在某些情况下,编译器可以优化'if'树来使用查找表。对于目前的编译器来说,这种情况的可能性要小得多,但并没有超出标准所说的。 – 2010-07-30 17:33:26