2011-01-30 67 views
5

我有一個問題,關於是否在一個函數中使用'case'或'ifs'被調用了很多。 下面是'ifs'中現在的情況。代碼是不言自明的:代碼優化;開關與if的

int identifyMsg(char* textbuff) { 
if (!strcmp(textbuff,"text")) { 
    return 1; 
} 
if (!strcmp(textbuff,"name")) { 
    return 2; 
} 
if (!strcmp(textbuff,"list")) { 
    return 3; 
} 
if (!strcmp(textbuff,"remv")) { 
    return 4; 
} 
if (!strcmp(textbuff,"ipad")) { 
    return 5; 
} 
if (!strcmp(textbuff,"iprm")) { 
    return 6; 
} 
return 0; 
} 

我的問題是:交換機的性能會更好嗎?我知道如果使用'ifs',我可以將最有可能的選項放在頂部。

+0

看到這個:http://stackoverflow.com/questions/97987/switch-vs-if-else – Nawaz 2011-01-30 12:53:26

+1

你應該把精力集中在你的代碼正確的,你不用擔心微觀優化前。一旦這是正確的,你應該優化之前進行測量。然後當你認爲你需要優化時,你應該考慮優化代碼的未來可維護性。簡而言之,優化代碼是不正確的。 – 2011-01-30 12:57:56

回答

10

對於字符串,您不能使用switch語句,因爲它們是指針,並且不會在編譯時進行評估。 您被困在使用一堆if語句。

但是出於性能的考慮,我認爲當有更多的條件需要檢查時,開關的性能會更好,但差異會非常小,無關緊要。

我以前從來沒有測試,雖然這一點,但我已經知道了這種開關的優化:

switch (value) { 
    case frequent_value1: 
    case frequent_value2: 
    case frequent_value3: 
    break; 

default: 
    switch (value) { 
    case infrequent_value1: 
    case infrequent_value2: 
    case infrequent_value3: 
     break; 
    } 
} 
+0

確實。但除此之外:即使有可能,「哪個表現更好」這個問題也沒有意義。 – delnan 2011-01-30 12:51:42

+0

關於SO的另一個好主題:http://stackoverflow.com/questions/97987/switch-vs-if-else – Nawaz 2011-01-30 12:52:35

+3

這些嵌套的交換機不應該有任何積極的性能影響。如果發生其中一種常見情況,則無論如何都不會檢查任何其他情況的情況。普通的if-elseif也是如此。 – Thorarin 2011-01-30 12:58:07

5

可能使用gperf產生的「動詞」的完美哈希要看到。然後你可以使用switch聲明。

或者,你可以做這樣的事情:

switch (textbuff[0]) 
{ 
    case 'i': 
    { 
     switch (textbuff[1]) 
     { 
      case 'p': 
      { 
       switch (textbuff[2]) 
       { 
        case 'a': /* something. */ break; 
        case 'r': /* something else. */ break; 
       } 
      } 
     } 
    } 

(你的想法)。

作爲另一種選擇(如果您所有的命令都是4個字符),使之成爲一個32位的號碼,然後在該切換:

int32_t mashed = 
    textbuff[0] << 24 | 
    textbuff[1] << 16 | 
    textbuff[2] << 8 | 
    textbuff[3]; 

switch (mashed) { /* ... */ } 

說實話,不過,除非列表的選項特別大,或者這個函數被稱爲猥瑣的次數,這不值得。

記住:先測量;稍後優化(僅在必要時)。

2

你可以很好地使用這些字符串的「枚舉」。然後使用switch case語句。

2

,我所遇到的最近這可能會或可能不適合你的喜好另一種方法是:

int identifyMsg(const char* textbuff) { 
    static const struct { const char* str; int id; } pairs[] = { 
     { "text", 1 }, 
     { "name", 2 }, 
     { "list", 3 }, 
     { "remv", 4 }, 
     { "ipad", 5 }, 
     { "iprm", 6 }, 
    }; 
    for (int i = 0; i < sizeof(pairs)/sizeof(pairs[0]); ++i) { 
     if (!strcmp(textbuff, pairs[i].str)) 
      return pairs[i].id; 
    } 
    return 0; 
} 
2

有兩個問題,據我瞭解。優化和如果/切換。

首先,代碼優化是一個代價高昂的過程。只優化代碼的那些部分,這些部分是明顯的瓶頸。在這種情況下,我懷疑它。看起來,就像你在發送一個文本標識來決定如何處理消息一樣。信息從哪裏來? IPC,XML,文件?你打算怎麼處理這個消息?性能如何是消息內容處理代碼?代碼中應該有地方,比字符串比較需要更多的資源。

您是否嘗試過一些性能分析器,如Purify,gperf,cachegrind?

關於if/switch:switch僅適用於整數類型。(字符,短,整型,長,枚舉)

2

假設它實際上事項:

因爲STRCMP是緩慢的,但整數比較快:如果您所有的命令都是4個字符 - 這恰好適應一個32位的整數 - 你可以將每個字符串轉換爲一個32位的數字,然後根據它進行切換。

否則,有兩種基本方式快速比較字符串對很多候選串:

  • 商店在哈希表中的候選人。

  • 排序候選以陣列按字母順序排序。然後,您可以使用strcmp的結果在數組上執行二分搜索,以查找匹配項,或排除剩餘候選項的一半。

作爲邊注 - 編譯器,諸如MSVC和GCC,已經實現了對測試使用二進制搜索的開關條件開關的優化。因此,一個包含256個元素的switch語句將被優化到最多8個比較操作。

4

你可以把所有的值放到一個std :: map中。

class MessageMap 
{ 
    std::map<std::string,int> data; 
    public: 
     MessageMap() 
     { 
      data["text"] = 1; 
      data["name"] = 2; 
      data["list"] = 3; 
      data["remv"] = 4; 
      data["ipad"] = 5; 
      data["iprm"] = 6; 
     } 
     int getMessageId(std::string const& index) cosnt 
     { 
      std::map<std::string,int>::const_iterator f; 
      if ((f = data.find(index)) != data.end()) 
      { 
       return f->second; 
      } 
      return 0; 
     } 
}; 
int identifyMsg(char* textbuff) 
{ 
    static MessageMap mssageMap; 
    return messageMap.getMessageId(textbuff); 
}