定义SOMETHING(1 <&lt; 0)

时间:2013-02-26 17:23:19

标签: c

我遇到了这行代码:

#define CPARSER_FLAGS_DEBUG        (1 << 0)

它做什么?它与以下相同:

#define CPARSER_FLAGS_DEBUG        (1)

右?

3 个答案:

答案 0 :(得分:16)

是的,确实如此。也许它在设置flags的值时用于对称:

#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) { /* ... */ }

答案 1 :(得分:10)

通常这样做是为了表明定义代表一个位标志。 ESP。当有多个标志一起定义时。在这种情况下,移位的大小定义了定义所代表的位位置。这样定义也可以很好地排列:

#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;

然后使用位01(FOO&amp; BAR)调用该函数并检查返回以查看是否设置了位2(BAZ)。

答案 2 :(得分:9)

在C语言中,<<>>运算符是左右bitwise shift运算符(尽管在C ++中它们可以重载 - 最着名的重载可能是{{3} })。例如,

x = y << 2;

将x向左移位两位的结果赋予x。

通常你会在低级代码中看到很多字节移位,这就是为什么......任何硬件提供了一种配置和控制其行为的方法,但是没有人想用整个整数来表示,比如ON /关闭状态。因此,硬件开发人员通常提供单个整数(也称为寄存器,通常是无符号32位),并指出例如位#0启用或禁用数据传输,位#1启用或禁用数据过滤,位#3执行一些其他的魔法,所以一个和所以力量。通常,可以同时读取或更改一个或多个设置。现在想象一下软件开发人员有多方便 - 程序员不必使用简单的整数(或布尔值),而是处理通常无法通过CPU寻址的位。为了简化生活,开发人员定义了掩码。坚持上面的例子,配置掩码可能如下所示:

#define MYDEV_ENABLE_DATA_FLOW (1u<<0)
#define MYDEV_ENABLE_FILTERING (1u<<1)
#define MYDEV_ENABLE_MAGIC     (1u<<2)

由于shift表达式的右侧是已知的,编译器将分别为每个值生成以下整数:

  • 1
  • 2
  • 4

起初可能没什么意义,但如果你看一下二进制表示中的那些值,看起来像这样:

  • 项目0B001
  • 0b010
  • 0b100时

换句话说,每个值只有一个位设置在不同的位置。然后,假设我们想要启用数据传输和魔术功能,但不启用对我们想象设备的过滤。为此,我们必须只设置#0和#2位(1),并且#1位未设置(0)。这是I/O stream operators运算符和我们的预定义掩码一起使用的时候。我们做的是:

uint32_t value_for_device = MYDEV_ENABLE_DATA_FLOW | MYDEV_ENABLE_MAGIC;

哪个“或”0b0010b100,给予0b101值。我们将其发送到设备,它会检查每一位并启用或禁用相应的功能。

通常也使用其他位操作。比如说,我们不知道当前启用或禁用了什么,我们不想更改任何内容,只需确保数据过滤已关闭。这可以通过读取当前配置,取消设置位并将其写回来完成。例如:

uint32_t value;
value = read_from_device();
value &= (~MYDEV_ENABLE_FILTERING);
write_to_device(value);

这当然不是唯一的用法。有关许多有用的示例,请参阅Bitwise OR

好的,回到原来的问题 - 为什么要写(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

可维护性

易于改变的事物

它可以更容易地改变现状。通过仅改变移位宽度而不是继续添加/移除'&lt;更容易改变周围的事物。

意图表达

它明确说明了作者阅读代码的意图。只是1并不意味着什么。但是当你看到1<<0时,你很可能会认为涉及到位移,并且代码可以使用位掩码。

灵活性

想象一下,应该执行移位的数量被定义为宏。例如:

#define MY_BIT (1u<<MAGIC_BIT_OFFSET)

然后,你真的不知道结果是1。您可以单独保留位偏移定义。

可能有更多理由要做到这一点,我不会马上想到这一点。

希望它清除的内容。祝你好运!