为什么在c++中使用Bitwise操作
Why using Bitwise operations in c++
我很难理解为什么在枚举中使用位操作然后在代码中。为什么不只使用数字或布尔值例如:
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;
}
}
这不是关键或嵌入式软件。
使用位而不是布尔值的优点是可以直接操作值集。例如定义:
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");
即直接传递值的子集。
使用容器而不是单个整数参数将需要更多的代码来写入和读取。这也会降低效率,但在某些情况下,这并不是最重要的一点。
这些枚举值是位字段中使用的标志(此处为_bits
)。通过声明布尔值的结构可以获得类似的行为:
struct field {
bool rs_blend;
bool rs_blend_func;
...
};
然而,这样的结构每个条目至少需要一个字节,而且处理起来很困难,因此开发人员采用了不同的方法,将这些值编码为整数值的位。
任何值为1的整数都设置了"最右边"(最低有效位),因此1 << i
的第i
位恰好等于1,这意味着该枚举中的每个常数(RS_BLEND
、RS_BLEND_FUNC
)都编码一位。这实际上是一个相当常见的习惯用法,尤其是在C中,处理结构要详细得多。
通过使用逐位操作,可以在该位字段中一次设置或清除etc。例如,RS_BLEND | RS_BLEND_FUNC
创建了一个位字段,该字段恰好设置了这两个标志。有关在此上下文中使用逐位操作的详细信息,请参阅此线程。
这很方便。
在示例代码中,显然(包括注释中的内容)至少有12个不同的设置,每个设置都是打开或关闭的,但也可以组合打开或关闭。
位篡改允许打开或关闭单独设置的组(包括一组),或者测试特定组是否打开或关闭,而不必大惊小怪。
数值和数值运算可以做到这一点,但并不方便。
例如,使用测试CULL_FACE和DEPTH_FACE设置中是否至少有一个处于打开状态更容易(也不容易出错)
if (flags & (RS_CULL_FACE | RS_DEPTH_FACE))
而不是跟踪所有可能的数值,这两个设置中的一个可能为真,并针对每一个进行测试。
如果使用布尔值,则为1位,而不是8位。使用1/8的内存来表示完全相同的数据是一个相当惊人的节省(仅仅因为有人对按位操作感到不舒服而使用8倍的内存同样是令人难以置信的浪费),如果你在处理循环中频繁访问的热数据,这可能很重要(例如,我的i7上每个核心的L1缓存只有64KB,更不用说有限的寄存器了)。
此外,如果您在这里使用位,您可以测试用单个指令设置的两个或多个位。您还可以同时使用FFZ/FFS在64位中有效地找到空闲位或设置位。你可以很容易地一次反转64位,而不是循环通过64个布尔值,并且必须一次执行一个布尔值——这不仅对CPU来说效率非常高,而且对开发人员来说,当他只需要使用一个运算符时,编写所有代码的效率和生产效率也会降低。
好处还在继续。我实际上认为应该有更多的人使用比特操作,而不是更少。习惯用比特来思考需要一些时间,但并不需要太长时间。
- 为什么在popback()操作之后,它仍然打印完整的矢量
- 重载操作程序时出错>>用于类中的字符串 memebr
- 对字符串进行位操作
- 我可以在 C++ 中的函数体之外进行操作吗?
- MPI突然停止了对多个核心的操作
- 如何在信号处理程序和普通函数中对全局变量进行互斥读写操作
- 对字符数组中的元素执行逐位操作
- 如何在directx/c++中进行平移/缩放操作
- 逐位操作的隐式类型转换
- 为什么一个向量上的多线程操作很慢
- 排序时无法执行交换操作.我做的时候它会崩溃.为什么
- 位移操作和位掩码未检测到重复字符
- 如何进行特定的位操作?
- 当我们进行一些操作时,应该使用什么'std::string'或'std::stringstream'?
- 字符串操作 - 字符计数
- 此代码中的操作流程是什么?C/C++.
- 复制和交换习惯用法与移动操作之间的交互
- 像union_这样的 Boost.Geometry 操作如何处理浮点类型的基本不精确性?
- 为什么 std::lerp 不适用于任何已实现所需操作的类型?
- 为什么在c++中使用Bitwise操作