【问题标题】:Avoid a repeating and simple switch case in C/C++?在 C/C++ 中避免重复和简单的 switch case?
【发布时间】:2016-06-12 21:53:24
【问题描述】:

我在互联网上找到了一段代码,它的目标非常简单,但它使用了一种丑陋的方法。据说,作者正在使用 switch case 来确定先前定义的 Enum 的一些(非连续)值是否属于它们的范围。如果是,该函数将返回true,仅此而已。否则返回false

实际上是这样的:

switch(value) {
case ONE:
case TWO:
/* many similar lines later */
case TWENTY:
case TWENTY_FIVE:
/* an afternoon later */
case ONE_HUNDRED:
    return true;
default:
    return false;
}

由于编译器生成了一个跳转表,他们使用 switch case 是合理的(即使跳转表并不一定意味着从我收集的内容中即时查找)。即便如此,这还是会产生无数不必要的代码行。

我已阅读有关函数内联和使用函数指针数组的信息,但我不知道如何在这种特定情况下使用它。

我如何避免用这样一个简单的案例(没有双关语)写很多case X:

【问题讨论】:

  • 过长的 switch 和/或 if 语句通常表明 OOP 使用不当
  • @henrikgiesel,OOP 从何而来?
  • 您的问题到底是什么?我不明白。
  • if (value > ONE && value < ONE_HUNDRED)?
  • 您希望通过使用函数指针数组获得什么?如果函数指针数组比开关快,编译器开发人员将开始使用函数指针实现开关......

标签: c++ switch-statement boilerplate jump-table


【解决方案1】:

根据某个绑定整数有效地计算布尔值是位旋转的工作:

const unsigned long long ps[2] = {0x28208a20a08a28ac, 0x800228a202088288};

bool is_prime(unsigned x)
{
    return (x < 128) && ((ps[x >> 6] >> (x & 63)) & 1);
}

如果查看存储在数组中的数字的二进制表示,1 位表示素数,0 位表示复合数:

   2    8    2    0    8    a    2    0    a    0    8    a    2    8    a    c
0010 1000 0010 0000 1000 1010 0010 0000 1010 0000 1000 1010 0010 1000 1010 1100
    59             47     41           31        23     17      11      5   2
 61        53           43     37        29           19     13       7    3

要将其扩展到超过 128 个数字,只需增加数组大小并修补 is_prime 中的 &lt; 比较。常量 6 和 63 源于 unsigned long long 中的位数。

【讨论】:

  • 但是小游戏有点吓人:/
  • 您是否记得0x28208a20a08a28ac 用于此用途? ,所以小玩意需要记住/复制粘贴十六进制数字?
  • @AngelusMortis 不,我写了a program 来生成数字。
【解决方案2】:

在 C/C++ 中避免重复和简单的 switch case?

是的,请避免这种情况。您通常应该在任何给定的域/上下文中以最高抽象级别工作,无论是编译时多态性(例如使用模板)、面向对象编程还是更简单的控制结构.. 首先是正确性、代码清晰性和效率,然后是优化(并且只有在适当的测量之后)

在这种特殊情况下,您可以简单地这样做:

return (value < 100);

我不明白为什么 100 多行 switch 语句更好.. 即使它更快(这只是在没有实际测量的情况下的假设)它只会稍微快无论如何,它值得这么大惊小怪吗?不,或者至少在大多数现实生活场景中都没有。如果应用程序如此关键,那么优化这样的代码最好用汇编语言来完成。

至于函数内联和函数指针数组 - 我不确定我是否理解问题所在,但是,如果您不了解如何使用这些特性进行优化,请不要使用它们。让编译器优化您的代码。

【讨论】:

  • 不是 C/C++ 专家,为什么 switch 语句会更快?据我了解,它必须比较value 100 次,而if 只比较一次。
  • 考虑到并非所有枚举值都出现在此列表中(也就是它们不连续),我可以使用,正如@RodrigoGuiotti 建议的那样,比较每个“一堆”枚举值的末端.
【解决方案3】:

由于您有一个奇数枚举,跳过值,您可以反转您的解决方案。 但是你需要声明跳过的数字(如果它只跳过几个)。

if( value > ONE_HUNDRED || value < ONE )
{
    return false;
}
else
{
    switch(value)
    {
         case SKIPPED_FIRST:
         case SKIPPED_SECOND:
         {
             return false;
         }
         break;
         default:
         {
             return true;
         }
    }
}

【讨论】:

  • 我认为您的其他建议最好;这个答案为大量跳过的值提供了更多代码声明。
  • 您忘记了关键字case:语法错误。
猜你喜欢
  • 1970-01-01
  • 2012-09-13
  • 1970-01-01
  • 1970-01-01
  • 2020-06-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-14
相关资源
最近更新 更多