为什么在c ++中使用Bitwise操作

时间:2015-11-21 07:26:40

标签: c++ bitwise-operators

我很难理解为什么在枚举中使用Bitwise操作 然后在代码中。 为什么不使用数字或布尔值 例如:

enum
{
    RS_BLEND = (1 << 0),
    RS_BLEND_FUNC = (1 << 1),
    RS_CULL_FACE = (1 << 2),
    RS_DEPTH_TEST = (1 << 3),
    RS_DEPTH_WRITE = (1 << 4),
    RS_DEPTH_FUNC = (1 << 5),
    RS_CULL_FACE_SIDE = (1 << 6),
//            RS_STENCIL_TEST = (1 << 7),
//            RS_STENCIL_WRITE = (1 << 8),
//            RS_STENCIL_FUNC = (1 << 9),
//            RS_STENCIL_OP = (1 << 10),
    RS_FRONT_FACE = (1 << 11),

    RS_ALL_ONES = 0xFFFFFFFF,
};


void RenderState::StateBlock::setCullFace(bool enabled)
{
    _cullFaceEnabled = enabled;
    if (!enabled)
    {
        _bits &= ~RS_CULL_FACE;
    }
    else
    {
        _bits |= RS_CULL_FACE;
    }
}

这不是关键或嵌入式软件。

4 个答案:

答案 0 :(得分:4)

使用位而不是布尔值的优点是您可以直接操作值集。例如,定义:

const int FILLED  = (1 << 0);
const int STROKED = (1 << 1);
const int SHADOW  = (1 << 2);
const int BLINK   = (1 << 3);

您可以使用接受draw_mode参数的函数并将其称为

draw_symbol(FILLED | SHADOW | BLINK, "X");

即。直接传递值的子集。

使用容器而不是单个整数参数将需要更多代码来编写和读取。效率也会降低,但在某些情况下,这不是最重要的一点。

答案 1 :(得分:1)

这些枚举值是位域中使用的 flags (此处为_bits)。通过声明布尔结构可以获得类似的行为:

struct field {
    bool rs_blend;
    bool rs_blend_func;
    ...
};

但是,这样的结构每个条目至少需要一个字节,并且难以处理,因此开发人员通过将这些值编码为整数值的位来采用不同的方法。

值为1的任何整数都设置了“最右侧”(最低有效)位,因此1 << i恰好i位等于1,这意味着该枚举中的每个常量(RS_BLENDRS_BLEND_FUNC)编码一位。这实际上是一个相当普遍的习惯用法,特别是在C中,处理结构更加冗长。

通过使用按位运算,可以在此位域中立即设置或清除等。例如,RS_BLEND | RS_BLEND_FUNC创建一个具有这两个标志集的位域。有关在此上下文中使用按位运算的详细信息,请参阅this主题。

答案 2 :(得分:0)

如果您使用布尔值,则

1位与8位。使用1/8内存是一个相当惊人的节省来代表完全相同的数据(并且使用8倍以上只是因为有些人对按位操作感到不舒服同样非常浪费),如果你经常处理热数据这可能很重要循环访问(我的i7上每个核心的L1缓存只有64KB,例如,更不用说有限的寄存器了)。

此外,如果在此处使用位,则可以测试使用单条指令设置的两个或更多位。您还可以使用FFZ / FFS一次有效地找到64位中的空闲位或设置位。您可以轻松地反转,例如,一次64位,而不是循环通过64个布尔值,并且必须同时执行该操作,这不仅对CPU非常有效,而且开发人员写出所有内容的效率和效率也较低那个代码,当他只能使用一个操作符时。

好处不断。我实际上认为更多的人应该使用按位操作,而不是更少。需要一些时间来习惯用比特来思考,但这不需要太长时间。

答案 3 :(得分:0)

很方便。

在示例代码中,显然(包括注释中的内容)至少有12个不同的设置,每个设置都打开或关闭,但可以组合打开或关闭。

比特摆弄允许打开或关闭各个设置组(包括一组),或者测试特定组是否开启或关闭。

数字值和数字操作可以做到这一点,但不是那么方便。

例如,如果使用

打开CULL_FACE和DEPTH_FACE设置中的至少一个,则更容易(并且不易出错)
 if (flags & (RS_CULL_FACE | RS_DEPTH_FACE))

跟踪这两个设置可能为真的所有可能数值,并对每个设置进行测试。