代码优化;切换与if

时间:2011-01-30 12:47:26

标签: c++ if-statement switch-statement optimization

我有一个关于是否在一个被调用的函数中使用'case'或'ifs'的问题。 现在是'ifs'中的以下内容;代码不言自明:

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',我可以将最有可能的选项放在顶部。

7 个答案:

答案 0 :(得分: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;
     }
}

答案 1 :(得分: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 :(得分: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);
}

答案 3 :(得分:2)

你可以很好地使用“enum”来表示这些字符串。然后使用switch case语句。

答案 4 :(得分: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;
}

答案 5 :(得分:2)

据我所知,有两个问题。优化和if / switch。

首先,代码优化是一个代价高昂的过程。仅优化代码的那些部分,这显然是瓶颈。我怀疑在这种情况下。看起来像是在发送textual-id来决定如何处理消息。消息来自哪里? IPC,XML,文件?你打算怎么处理这条消息?消息内容处理代码的性能如何?代码中应该有一些地方,比字符串比较需要更多的资源。

您是否尝试过一些性能分析器,如Purify,gperf,cachegrind?

关于if / switch:switch是否仅适用于整数类型。 (char,short,int,long,enum)

答案 6 :(得分:2)

假设它确实很重要:

因为strcmp很慢,但是整数比较很快:如果所有命令都是4个字符长 - 恰好适合32位整数 - 你可以将每个字符串转换为32位数字,然后根据它进行切换。

否则,有两种基本方法可以快速将字符串与许多候选字符串进行比较:

  • 将候选人存储在哈希表中。

  • 按字母顺序对候选人进行排序。然后,您可以使用strcmp的结果对数组执行二进制搜索,以查找匹配项,或排除剩余候选项的一半。

作为旁注 - 编译器(如MSVC和GCC)已在使用二进制搜索测试交换机条件的交换机上实施了优化。因此,具有256个元素的switch语句将被优化到最多8个比较操作。