代码优化; switch 与 if 的比较

发布于 2024-10-14 23:51:06 字数 484 浏览 3 评论 0原文

我有一个关于在经常被调用的函数中是否使用“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”,我可以将最有可能的选项放在顶部。

I have a question about whether to use 'case' or 'ifs' in a function that gets called quite a lot.
Here's the following as it is now, in 'ifs'; the code is self-explanatory:

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;
}

My question is: Would a switch perform better? I know if using 'ifs', I can place the most likely options at the top.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

不甘平庸 2024-10-21 23:51:06

您不能对字符串使用 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;
     }
}

You can't use switch statements for strings because they are pointers and are not evaluted at compile time.
You are stuck with using a bunch of if statements.

However for the sake of performance, I believe switches perform better when there are more conditions to check but the difference will be so minute it wouldn't matter.

I've never tested this before though, but I've read about this kind of switch optimization:

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;
     }
}
拿命拼未来 2024-10-21 23:51:06

可以使用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) { /* ... */ }

不过,老实说,除非选项列表特别大,或者此功能正在使用被骂了多次,就不值得了。

记住:先测量;稍后优化(仅在必要时)。

You could use gperf to generate perfect hashes of the "verbs" you want to see. Then you could use a switch statement.

Or, you could do something like this:

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

(You get the idea).

As yet another option (if all of your commands are 4 characters), turn them into a single 32-bit number and then switch on that:

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

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

To be honest, though, unless the list of options is particularly large, or this function is being called an obscene number of times, it won't be worth it.

Remember: measure first; optimise later (only if necessary).

财迷小姐 2024-10-21 23:51:06

您可以将所有值放入 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);
}

You could put all the values into a 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);
}
孤单情人 2024-10-21 23:51:06

您可以很好地对这些字符串使用“enum”。然后使用 switch case 语句。

You could very well use "enum" for those strings. then use switch case statements.

爱殇璃 2024-10-21 23:51:06

据我了解,有两个问题。优化和 if/switch。

首先,代码优化是一个成本高昂的过程。仅优化那些明显是瓶颈的代码部分。在这种情况下我对此表示怀疑。看起来,您正在发送一个文本 ID 来决定如何处理消息。消息从哪里来? IPC、XML、文件?您打算如何处理此消息?消息内容处理代码的性能如何?代码中应该有一些地方比字符串比较占用更多的资源。

您是否尝试过 Purify、gperf、cachegrind 等性能分析器?

关于 if/switch: switch 仅适用于整数类型。 (字符、短、整数、长、枚举)

There were two questions, as far as I understood. Optimization and if/switch.

First of all, code-optimization is a costly process. Optimize only those parts of code, which are bottle-necks by evident. I doubt it in this case. Looks, like you are dispatching a textual-id for making a decision what to do with a message. Where does the message come from? IPC, XML, File? What are you going to do with this message? How performant is the message-content processing-code? There should be places in code, which take more ressources than string comparison.

Have you tried out some performance analyzers like Purify, gperf, cachegrind?

Concerning if/switch: switch works only with integer-types. (char, short, int, long, enum)

囍笑 2024-10-21 23:51:06

我最近遇到的另一种选择可能符合您的喜好,也可能不符合您的喜好:

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;
}

Another alternative that I have come across recently which might or might not fit your liking is:

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;
}
拥抱没勇气 2024-10-21 23:51:06

假设它实际上很重要:

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

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

  • 将候选字符串存储在哈希表中。

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

附带说明 - 编译器(例如 MSVC 和 GCC)已经对开关进行了优化,使用二分搜索来测试开关条件。因此,具有 256 个元素的 switch 语句将被优化为最多 8 个比较操作。

Assuming it actually matters:

Because strcmp is slow, but an integer compare is fast: if all your commands are 4 characters long - which happens to fit in a 32bit integer - you can cast each string to a 32bit number, and then switch based on that.

Otherwise, there are two basic ways to quickly compare a string against a lot of candidate strings:

  • Store the candidates in a hash table.

or

  • Sort the candidates alphabetically sorted in an array. You can then perform a binary search on the array by using the result of strcmp to either find a match, or exclude half of the remaining candidates.

As a side note - Compilers, such as MSVC and GCC, have implemented an optimization on switches that tests the switch conditions using a binary search. So a switch statement with, say, 256 elements, will be optimized down to, at most, 8 compare operations.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文