【问题标题】:How do you use bitwise flags in C++?如何在 C++ 中使用按位标志?
【发布时间】:2009-02-13 18:05:08
【问题描述】:

根据this 网站,我希望用 16 位整数的二维数组来表示迷宫。

每个 16 位整数需要保存以下信息:

这里有一种方法(这绝不是唯一的方法):一个 12x16 的迷宫网格可以表示为一个 16 位整数的数组 m[16][12]。每个数组元素将包含网格中单个对应单元格的所有信息,整数位映射如下:


(来源:mazeworks.com

要推倒一堵墙、设置边界或创建特定路径,我们需要做的就是翻转一个或两个数组元素中的位。

如何在 16 位整数上使用按位标志,以便我可以设置每个位并检查它们是否已设置。

我想以一种易于阅读的方式(即 Border.W、Border.E、Walls.N 等)来实现。

这通常在 C++ 中是如何完成的?我是否使用十六进制来表示每一个(即 Walls.N = 0x02、Walls.E = 0x04 等)?我应该使用枚举吗?


另见How do you set, clear, and toggle a single bit?

【问题讨论】:

    标签: c++ bit-manipulation


    【解决方案1】:

    如果您想使用位域,那么这是一种简单的方法:

    typedef struct MAZENODE
    {
        bool backtrack_north:1;
        bool backtrack_south:1;
        bool backtrack_east:1;
        bool backtrack_west:1;
        bool solution_north:1;
        bool solution_south:1;
        bool solution_east:1;
        bool solution_west:1;
        bool maze_north:1;
        bool maze_south:1;
        bool maze_east:1;
        bool maze_west:1;
        bool walls_north:1;
        bool walls_south:1;
        bool walls_east:1;
        bool walls_west:1;
    };
    

    然后你的代码可以测试每一个的真假。

    【讨论】:

    • 不幸的是,这是不可移植的,因为位的顺序是编译器特定的。
    • 另外,我不确定 bool 是否是位域支持的类型,如果使用 unsigned 会更便携。
    • 是的,位域支持 bool,但你是对的,它们的顺序完全取决于编译器,通常与字节序相关
    • 除非你想在机器之间发送这个二进制数据结构,或者将它存储到一个文件中并用另一个程序读回,否则位的顺序并不重要。所以这得到了我的 +1 票。
    • 如果您可以将 n,s,e,w 字段嵌套到内部结构中会更好。
    【解决方案2】:

    使用std::bitset   

    【讨论】:

      【解决方案3】:

      如果您关心特定位的含义,请使用十六进制常量/枚举和按位运算。

      否则,请使用 C++ 位域(但请注意,整数中位的顺序将取决于编译器)。

      【讨论】:

        【解决方案4】:

        了解您的位运算符:&、|、^ 和 !。

        在许多 C/C++ 文件的顶部,我看到了以十六进制定义的标志来屏蔽每一位。

        #define ONE 0x0001
        

        要查看某个位是否打开,您可以将其与 1 进行“与”。要打开它,您可以将其与 1 进行或。要像开关一样切换,请与 1 进行异或。

        【讨论】:

          【解决方案5】:

          要操作位集,您还可以使用 ....

          std::bitset<N>

          std::bitset<4*4> bits;
          bits[ 10 ] = false;
          bits.set(10);
          bits.flip();
          assert( !bits.test(10) );
          

          【讨论】:

            【解决方案6】:

            您可以按照您的建议使用十六进制标志或枚举来执行此操作,但最易读/自记录的可能是使用所谓的“位域”(有关详细信息,请访问 Google for C++ bitfields)。

            【讨论】:

              【解决方案7】:

              是的,一个好方法是使用十六进制十进制来表示位模式。然后使用位运算符来操作 16 位整数。

              例如:

              if(x & 0x01){} // tests if bit 0 is set using bitwise AND
              x ^= 0x02;     // toggles bit 1 (0 based) using bitwise XOR
              x |= 0x10;     // sets bit 4 (0 based) using bitwise OR
              

              【讨论】:

                【解决方案8】:

                我不是 bitset 的忠实粉丝。在我看来,这只是更多的打字。无论如何,它并没有隐藏你在做什么。你还是要 & && |位。除非您只选择 1 位。这可能适用于一小组标志。并不是说我们也需要隐藏我们正在做的事情。但是一个类的目的通常是让它的用户更容易做一些事情。我不认为这门课能做到。

                例如,您有一个带有 .. 64 个标志的标志系统。如果您想测试..我不知道.. 1 if 语句中的 39 个以查看它们是否都在...使用位域是一个巨大的痛苦。你必须把它们都打出来……当然。我假设您使用 only 位域功能而不是混合和匹配方法。与位集相同。除非我在课堂上遗漏了一些东西。这是很有可能的,因为我很少使用它。我看不到一种可以测试所有 39 个标志的方法,除非你输入洞的东西或诉诸“标准方法”(使用枚举标志列表或 39 位的一些定义值并使用位集 && 运算符)。根据您的方法,这可能会开始变得混乱。我知道.. 64 个标志听起来很多。好吧。它是..取决于你在做什么。就个人而言,我参与的大多数项目都依赖于标志系统。所以实际上.. 64 并不是闻所未闻的。虽然 16~32 在我的经验中更为常见。实际上,我现在正在帮助一个标志系统具有 640 位的项目。它基本上是一个特权系统。所以把它们安排在一起是有道理的……但是……不可否认……我想把它分解一下……但是……嗯……我是在帮助……而不是创造。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2012-11-18
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2011-11-23
                  • 1970-01-01
                  相关资源
                  最近更新 更多