2011-01-30 39 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); 
}