位掩码 switch 语句

发布于 2024-11-19 00:19:00 字数 1055 浏览 3 评论 0原文

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

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

int bitmask = val1 | val3;

if(bitmask & val1)
    ...
if(bitmask & val2)
    ...
if(bitmask & val3)
    ...

这很好,并且工作完美,但我一直想知道是否可以通过开关来完成。我在想一些类似的事情:

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

所以我的问题是:

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

  • I have this code in a section of my project:

    enum myEnum
    {
        invalid = -1,
        val1 = 1,
        val2 = 2,
        val3 = 4
    };
    
    int bitmask = val1 | val3;
    
    if(bitmask & val1)
        ...
    if(bitmask & val2)
        ...
    if(bitmask & val3)
        ...
    

    This is fine, and it works perfectly, but i've always wondered if it could be done with a switch. I was thinking something along the lines this:

    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
    

    so my questions are:

  • have i just solved my problem? i suppose i have, but is it a clean solution?
  • is there a simpler way of accomplishing this?
  • is it a bad idea to mix #defines and functions?

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

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

    发布评论

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

    评论(7

    想你只要分分秒秒 2024-11-26 00:19:00

    不,这不是一个干净的解决方案,对于您的上下文,您可以避免混合 #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;
    }
    

    No it's not a clean solution and for your context, you can avoid mixing #define and functions. You can try below solution, if you want 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;
    }
    
    我乃一代侩神 2024-11-26 00:19:00

    不,这(显然)不是一个干净的解决方案。您的原始代码很简单,没有循环,并且不涉及向语言添加奇怪结构的特殊情况“秘密”宏。

    我所说的“奇怪的构造”是指 START_BITMASK_SWITCH()/END_BITMASK_SWITCH 宏,它:

    • 添加一个循环,而不使用任何标准关键字,甚至暗示正在发生循环
    • 当前作用域中的破坏者名称或多或少默默地
    • 包含一个虚假的分号

    这对您的解决方案没有任何好处,它所做的只是增加膨胀和开销(无论是在代码大小方面,以及复杂性和运行时性能)只是为了满足出于某种原因想要使用 switch 来做一些不太适合做的事情的渴望。

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

    No, it is (obviously) not a clean solution. Your original code was straight-forward, didn't loop, and didn't involve special-case "secret" macros that add weird constructs to the language.

    By "weird construct", I meant the START_BITMASK_SWITCH()/END_BITMASK_SWITCH macros, which:

    • Add a loop without using any of the standard keywords to even hint that a loop is happening
    • Clobber names in the current scope more or less silently
    • Include a spurious semi-colon

    There's no benefit to your solution, all it does is add bloat and overhead (both in terms of code size, and complexity, and run-time performance) just to scratch that itch of for some reason wanting to use a switch to do something that it's not very well-suited to do.

    Obviously, this is highly subjective, but you did ask.

    旧话新听 2024-11-26 00:19:00

    我看到了几个问题:

    • 它增加了预处理器的缺陷,但没有真正的好处
    • ;它添加了很多缓慢的代码(移位、循环、测试);
    • 它阻止您添加特殊情况,例如“如果位 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;
    }
    

    I see several problems:

    • it adds preprocessor cruft with no real benefit
    • it adds a lot of slow code (shifts, loops, tests)
    • it prevents you from adding special cases such as "if bit 2 is on and bit 3 is off" (if ((bitmask & (val2 | val3)) == val2))
    • the compiler will miss almost every possibility to optimise the generated code

    It can also be done in a much, much simpler way:

    #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;
    }
    
    爱已欠费 2024-11-26 00:19:00

    如果需要的话,位掩码只是一个布尔数组,而您的枚举就是索引。你能切换一个bool数组吗?不,你不能,因为它可以同时代表多个状态。您只能像使用任何整数一样切换整体位掩码。

    A bitmask is just an array of bools if you want, and your enum are the indices. Can you switch over an array of bool? No you can't, because it can represent multiple states at the same time. You could only switch over the overall bitmask like with any integer.

    ヤ经典坏疍 2024-11-26 00:19:00

    您可以创建一个 foreach 构造,在其中迭代位掩码的位并提供一个带有 switch 语句的函数。

    You could make a foreach construct where you iterate through the bits of your bitmask and provide a function with a switch statement in it.

    月亮是我掰弯的 2024-11-26 00:19:00

    当然可以,如果那是你真正想要的。如前所述,只有有限的情况,也许没有,您可能需要这样做。但你可以。

    #include <iostream>
    
    enum myEnum
    {
        invalid = -1,
        val1 = 1,
        val2 = 2,
        val3 = 4
    };
    
    int main()
    {
        const int bitmask = val1 | val3;
    
        switch (1) {
            case (bitmask & val1) : std::cout << "1"; break;
            case (bitmask & val2) : std::cout << "2"; break;
            case (bitmask & val3) : std::cout << "3"; break;
            default: break;
        }
    }
    

    Of course you can, if that's what you really want. As mentioned there are only limited cases, maybe none, where you may ever need to. But you can.

    #include <iostream>
    
    enum myEnum
    {
        invalid = -1,
        val1 = 1,
        val2 = 2,
        val3 = 4
    };
    
    int main()
    {
        const int bitmask = val1 | val3;
    
        switch (1) {
            case (bitmask & val1) : std::cout << "1"; break;
            case (bitmask & val2) : std::cout << "2"; break;
            case (bitmask & val3) : std::cout << "3"; break;
            default: break;
        }
    }
    
    心安伴我暖 2024-11-26 00:19:00
    enum Positions {
        ALPHA,
        BETA,
        GAMMA
    };
    
    enum Flag {
        ALPHA_FLAG == 1 << ALPHA,
        BETA_FLAG  == 1 << BETA,
        GAMMA_FLAG == 1 << GAMMA
    };
    
    Position position_of (Flag f) {
        unsigned n = f;
        unsigned i = 0;
        while ((n & 1) == 0) {
             ++i;
             n >>= 1;
        }
        return Position (i);
    }
    
    switch (position_of (flag)) {
        case ALPHA:
        case BETA:
        // ...
    };
    

    使用 C++0x 强枚举 会更好,那么您可以使用 Position::ALPHAFlag::ALPHA 进行更清晰的命名。您还可以使用 constexpr 安全地对您的 Flag 值进行位掩码。

    enum Positions {
        ALPHA,
        BETA,
        GAMMA
    };
    
    enum Flag {
        ALPHA_FLAG == 1 << ALPHA,
        BETA_FLAG  == 1 << BETA,
        GAMMA_FLAG == 1 << GAMMA
    };
    
    Position position_of (Flag f) {
        unsigned n = f;
        unsigned i = 0;
        while ((n & 1) == 0) {
             ++i;
             n >>= 1;
        }
        return Position (i);
    }
    
    switch (position_of (flag)) {
        case ALPHA:
        case BETA:
        // ...
    };
    

    This is nicer with C++0x strong enums, then you can have Position::ALPHA and Flag::ALPHA for clearer naming. You can also use constexpr to safely bitmask your Flag values.

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