我遇到了这行代码:
#define CPARSER_FLAGS_DEBUG (1 << 0)
它是做什么的?与此相同:
#define CPARSER_FLAGS_DEBUG (1)
对吗?
我遇到了这行代码:
#define CPARSER_FLAGS_DEBUG (1 << 0)
它是做什么的?与此相同:
#define CPARSER_FLAGS_DEBUG (1)
对吗?
是的,它可能用于在设置标志值时保持对称性:
#define FLAG_1 (1 << 0)
#define FLAG_2 (1 << 2)
#define FLAG_3 (1 << 3)
/* ... */
/* Flags FLAG_1, FLAG_2 and FLAG_3 are set. */
f = FLAG_1 | FLAG_2 | FLAG_3;
测试一个给定的标志是否被设置:
/* True if FLAG_1 is set. */
if (f & FLAG_1) { /* ... */ }
<<
和>>
运算符是左移和右移的位运算符(尽管在C ++中它们可以被重载-最著名的重载可能是I / O流运算符)。例如,x = y << 2;
将y左移两位的结果赋给x。
通常在低级代码中会看到很多字节移位,原因如下...任何硬件都提供一种配置和控制其行为的方式,但没有人想使用整数来表示开/关状态。因此,硬件开发人员通常提供单个整数(也称为寄存器,通常是无符号32位),并声明例如第0位启用或禁用数据传输,第1位启用或禁用数据过滤,第3位执行其他魔法等等。通常,可以同时读取或更改一个或多个设置。现在想象一下,这对软件开发人员有多方便-与简单的整数(或布尔值)不同,程序员必须处理通常不能由CPU寻址的位。为了简化他们的生活,开发人员定义掩码。坚持以上例子,配置掩码可能如下:
#define MYDEV_ENABLE_DATA_FLOW (1u<<0)
#define MYDEV_ENABLE_FILTERING (1u<<1)
#define MYDEV_ENABLE_MAGIC (1u<<2)
由于移位表达式的右侧已知,编译器将分别为每个值生成以下整数:
一开始可能不太有意义,但如果您以二进制表示查看这些值,则如下所示:
换句话说,每个值仅在不同位置上设置了一个位。然后,假设我们想要为我们的虚拟设备启用数据传输和魔术功能,但不启用过滤。 为此,我们只需要设置第#0和#2位(1
),并取消设置第#1位(0
)。 这是当按位或运算符与我们预定义的掩码一起使用时非常方便的地方。 我们这样做:
uint32_t value_for_device = MYDEV_ENABLE_DATA_FLOW | MYDEV_ENABLE_MAGIC;
以下是需要翻译的内容:
将 0b001
和 0b100
进行 "OR" 运算,得到 0b101
值。我们将此值发送到设备,它会检查每个位并启用或禁用相应的功能。
其他位运算也经常被使用。例如,假设我们不知道当前启用或禁用了哪些功能,但只想确保数据过滤已关闭。可以通过读取当前配置、取消设置该位并将其写回来来实现。例如:
uint32_t value;
value = read_from_device();
value &= (~MYDEV_ENABLE_FILTERING);
write_to_device(value);
(1<<0)
而不是简单地写(1)
?有很多原因:
#define A (1<<0)
#define B (1<<1)
#define C (1<<2)
不是这样:
#define A (1)
#define B (1<<1)
#define C (1<<2)
或者是这个:
#define A 1
#define B 2
#define C 4
It makes it easier to change things around. It is easier to change things around by only changing the shift width and not keep adding/removing '<
It clearly states the intent of the author to those who read the code. Just 1
does not mean much. But when you see 1<<0
you most likely assume that bit shifting is involved and the code works with bit-masks.
Imagine that the number by which the shift should be performed is defined as a macro. For example:
#define MY_BIT (1u<<MAGIC_BIT_OFFSET)
Then, you don't really know wether the result is 1
or not. And you can keep bit offset definitions separately.
There is probably some more reasons to do this that don't come to my mind straight away.
Hope it clears up things a bit. Good Luck!
(iu<<0)
== (i<<0)
,而(-1u>>0) != (-1 >> 0)
。 - Grijesh Chauhan通常这样做是为了表示定义代表一个位标志,特别是当有多个标志一起定义时。在这种情况下,移位的大小定义了该定义所代表的位位置。像这样定义也可以使事情很好地对齐:
#define FOO_FLAG (1 << 0)
#define BAR_FLAG (1 << 1)
#define BAZ_FLAG (1 << 2)
int ret = some_function(FOO_FLAG | BAR_FLAG) & BAZ_FLAG;
0
和1
(FOO&BAR)调用函数,并检查返回值以查看是否设置了位2
(BAZ)。
(1 << 0) == (1)
。实际上,(i << 0)
优化为i
或者(i >> 0)
优化为i
,就像(i | i)
一样被称为非表达式。 - Grijesh Chauhan1 + 0
等于1
。然而,以这种方式编写代码是为了向读者表明该值旨在用作位掩码(最低有效位为1,其余为0),而不是整数。 - Bogdan Alexandru