我来了accros这行代码:
#define CPARSER_FLAGS_DEBUG (1 << 0)
Run Code Online (Sandbox Code Playgroud)
它有什么作用?它与以下相同:
#define CPARSER_FLAGS_DEBUG (1)
Run Code Online (Sandbox Code Playgroud)
对?
md5*_*md5 16
是的.也许它在设置标志值时用于对称:
#define FLAG_1 (1 << 0)
#define FLAG_2 (1 << 2)
#define FLAG_3 (1 << 3)
/* ... */
Run Code Online (Sandbox Code Playgroud)
不要担心性能,好的编译器就能优化这样的操作.
您可以将这些值组合如下:
/* Flags FLAG_1, FLAG_2 and FLAG_3 are set. */
f = FLAG_1 | FLAG_2 | FLAG_3;
Run Code Online (Sandbox Code Playgroud)
并测试是否设置了给定标志:
/* True if FLAG_1 is set. */
if (f & FLAG_1) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)
Wil*_*ill 10
通常这样做是为了表明定义代表一个标志.ESP.当有多个标志一起定义时.在这种情况下,移位的大小定义了定义所代表的位位置.这样定义也可以很好地排列:
#define FOO_FLAG (1 << 0)
#define BAR_FLAG (1 << 1)
#define BAZ_FLAG (1 << 2)
Run Code Online (Sandbox Code Playgroud)
这可以在调用需要一系列标志的函数时使用:
int ret = some_function(FOO_FLAG | BAR_FLAG) & BAZ_FLAG;
Run Code Online (Sandbox Code Playgroud)
然后用位0
和1
(FOO&BAR)调用函数并检查返回以查看是否设置了位2
(BAZ).
小智 9
在C-启发的语言,<<
和>>
运营商都左,右按位移位运算符(虽然在C++中,他们可以被重载-最有名的超载可能是I/O流运营商).例如,
x = y << 2;
Run Code Online (Sandbox Code Playgroud)
分配x将y向左移位两位的结果.
通常你会在低级代码中看到很多字节移位,这就是为什么......任何硬件提供了一种配置和控制其行为的方法,但是没有人想用整个整数来表示ON/OFF状态.因此,硬件开发人员通常提供单个整数(也称为寄存器,通常是无符号32位),并指出例如位#0启用或禁用数据传输,位#1启用或禁用数据过滤,位#3执行一些其他的魔法,所以一个和所以力量.通常,可以同时读取或更改一个或多个设置.现在想象一下软件开发人员有多方便 - 程序员不必使用简单的整数(或布尔值),而是处理通常无法通过CPU寻址的位.为了简化生活,开发人员定义了掩码.坚持使用上面的示例,配置掩码可能如下所示:
#define MYDEV_ENABLE_DATA_FLOW (1u<<0)
#define MYDEV_ENABLE_FILTERING (1u<<1)
#define MYDEV_ENABLE_MAGIC (1u<<2)
Run Code Online (Sandbox Code Playgroud)
由于shift表达式的右侧是已知的,编译器将分别为每个值生成以下整数:
最初可能没有多大意义,但如果你在二进制表示中查看这些值,看起来像这样:
换句话说,每个值只有一个位设置在不同的位置.然后,假设我们想要启用数据传输和魔术功能,但不启用对我们想象设备的过滤.为此,我们必须只有#0和#2 1
位()和#1位未设置(0
).这是Bitwise OR运算符和我们预定义的掩码一起使用的时候.我们做的是这样的:
uint32_t value_for_device = MYDEV_ENABLE_DATA_FLOW | MYDEV_ENABLE_MAGIC;
Run Code Online (Sandbox Code Playgroud)
哪个"或" 0b001
和0b100
,给予0b101
价值.我们将其发送到设备,它检查每一位并启用或禁用相应的功能.
通常也使用其他位操作.比如说,我们不知道当前启用或禁用了什么,我们不想更改任何内容,只需确保数据过滤已关闭.这可以通过读取当前配置,取消设置位并将其写回来完成.例如:
uint32_t value;
value = read_from_device();
value &= (~MYDEV_ENABLE_FILTERING);
write_to_device(value);
Run Code Online (Sandbox Code Playgroud)
当然,这不是唯一的用法.有很多有用的例子,请参阅Sean Eron Anderson的"Bit Twiddling Hacks".
好的,回到原来的问题 - 为什么要写(1<<0)
而不是简单(1)
?原因有很多:
有这样的事情更加一致:
#define A (1<<0)
#define B (1<<1)
#define C (1<<2)
Run Code Online (Sandbox Code Playgroud)
而不是这个:
#define A (1)
#define B (1<<1)
#define C (1<<2)
Run Code Online (Sandbox Code Playgroud)
甚至这个:
#define A 1
#define B 2
#define C 4
Run Code Online (Sandbox Code Playgroud)
它可以更容易地改变现状.只更改移位宽度而不是继续添加/删除'<更容易更改周围的事物
它明确说明了作者阅读代码的意图.只是1
意义不大.但是当你看到1<<0
你时,你很可能会认为涉及到位移,并且代码可以使用位掩码.
想象一下,应该执行移位的数量被定义为宏.例如:
#define MY_BIT (1u<<MAGIC_BIT_OFFSET)
Run Code Online (Sandbox Code Playgroud)
然后,你真的不知道结果是否合适1
.您可以单独保留位偏移定义.
可能有更多的理由要做到这一点,我不会马上想到这一点.
希望它能稍微清理一下.祝好运!