位掩码切换语句

Tom*_*Tom 6 c++ bitmask bitwise-operators bit-masks switch-statement

我在我的项目的一部分中有这个代码:

enum myEnum
{
    invalid = -1,
    val1 = 1,
    val2 = 2,
    val3 = 4
};

int bitmask = val1 | val3;

if(bitmask & val1)
    ...
if(bitmask & val2)
    ...
if(bitmask & val3)
    ...
Run Code Online (Sandbox Code Playgroud)

这很好,它完美地工作,但我总是想知道是否可以通过开关完成.我在思考这个问题:

int checkMask(int& mask)
{
    for(int i = 0; mask; mask &= ~(1 << i++))
    {
        if(mask & (1 << i))
        {
            int ret = mask & (1 << i);
            mask &= ~ret;
            return ret;
        }
    }

    return invalid;
}

#define START_BITMASK_SWITCH(x) int xcopy = x; while(xcopy) { switch(checkMask(xcopy))
#define END_BITMASK_SWITCH };

int bitmask = val1 | val3;

START_BITMASK_SWITCH(bitmask)
{
    case val1:
        ...
        break;
    case val2:
        ...
        break;
    case val3:
        ...
        break;
}
END_BITMASK_SWITCH
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:

  • 我刚刚解决了我的问题吗?我想我有,但这是一个干净的解决方案吗?
  • 有没有更简单的方法来完成这个?
  • 混合#defines和函数是一个坏主意吗?

  • iam*_*ind 13

    不,它不是一个干净的解决方案,对于您的背景,您可以避免混合#define和功能.如果您愿意,可以尝试以下解决方案switch():

    int bitmask = val1 | val3;
    int mask = 1;
    while(bitmask)
    {
      switch(bitmask & mask)
      {
      case val1: ... break;
      case val2: ... break;
      case val4: ... break;
      case val8: ... break;
      }
      bitmask &= ~mask; 
      mask <<= 1;
    }
    
    Run Code Online (Sandbox Code Playgroud)

    • 当我在网站上滚动时,我发现这个答案是最干净的解决方案. (2认同)

    unw*_*ind 6

    不,它(显然)不是一个干净的解决方案.您的原始代码是直接的,没有循环,并且不涉及为该语言添加奇怪结构的特殊情况"秘密"宏.

    通过"奇怪的构造",我的意思是START_BITMASK_SWITCH()/ END_BITMASK_SWITCH 宏,其中:

    • 添加一个循环而不使用任何标准关键字,甚至暗示循环正在发生
    • Clobber在当前范围内或多或少默默地命名
    • 包括一个虚假的分号

    你的解决方案没有任何好处,它所做的就是增加膨胀和开销(在代码大小,复杂性和运行时性能方面),只是为了抓住因某些原因想要使用a switch来做某事的痒不太适合做.

    显然,这是非常主观的,但你确实问过.


    sam*_*var 5

    我看到几个问题:

    • 它没有真正的好处就增加了预处理程序的复杂性
    • 它增加了很多慢速代码(移位,循环,测试)
    • 它阻止您添加特殊情况,例如“如果第2 位打开而第 3位关闭”(if ((bitmask & (val2 | val3)) == val2)
    • 编译器几乎会错过优化生成代码的所有可能性

    也可以用一种非常简单的方法来完成它:

    #define START_BITMASK_SWITCH(x) \
        for (uint64_t bit = 1; x >= bit; bit *= 2) if (x & bit) switch (bit)
    
    int bitmask = val1 | val3;
    
    START_BITMASK_SWITCH(bitmask)
    {
        case val1:
            ...
            break;
        case val2:
            ...
            break;
        case val3:
            ...
            break;
    }
    
    Run Code Online (Sandbox Code Playgroud)