2010-07-29 82 views
6

我感興趣,如果有從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。

回答

6

有一個區別 - 與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

0

一個開關應該被編譯爲一個間接尋址的跳轉,而if語句的序列將是一個有條件的跳轉鏈。第一個是不變的時間;當然,你可以在一個if中放置更多的一般條件。

編輯:我應該提到,如果一些智能編譯器能夠檢測到ifs鏈中的所有條件都具有特定的簡單形式並轉換爲開關,我不會感到驚訝。我不知道他們是否會這樣做,但是您可以隨時反編譯並檢查。

8

是的,有差異。級聯的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

1

這將取決於編譯器如何選擇優化代碼。編譯器的代碼優化是一個巨大的領域。

要找到編譯器的確切答案,請確定如何使用它構建彙編代碼,並查看寫入該文件的不同彙編代碼。

這已經用一個編譯器完成了,你可以在這裏看到結果。 http://www.eventhelix.com/RealtimeMantra/Basics/CToAssemblyTranslation3.htm

但簡短的答案是肯定的。他們很可能會有所不同。

0

case語句可以被編譯爲「跳錶」,這可能會更快,如果有數十例和你執行這數百萬次。

0

如果選擇值是一個整數(它必須在C/C++中),那麼編譯器可以用跳轉表替換if是可能的。

3

根據標準,有幾處不同。

  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,比較是恆定積分值,並且它不是在一個時髦的方式使用,則該行爲可以是相同的。是否有編譯器會使用這種等同性是另一個問題。

0

+1 David Thomley的回答,因爲我真的覺得這是最完整的。

雖然缺少一件重要的事情,那就是case標籤必須是在編譯時評估的常量表達式。與if比較的兩側(如果您減少if語句)在運行時進行評估。

1

我來到了同樣的問題,所以我做了一些測試,這裏有一些結果使用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倍!)。