定义SOMETHING(1 << 0)

我来了accros这行代码:

#define CPARSER_FLAGS_DEBUG (1 << 0) 

它有什么作用? 它同样如下:

 #define CPARSER_FLAGS_DEBUG (1) 

对?

在C语言中, <<>>运算符是左右按位移位运算符(尽管在C ++中它们可以重载 - 最着名的重载可能是I / O流运算符 )。 例如,

 x = y << 2; 

分配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) 

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

  • 1
  • 2
  • 4

最初可能没有多大意义,但如果你在二进制表示中查看这些值,看起来像这样:

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

换句话说,每个值只有一个位设置在不同的位置。 然后,假设我们想要启用数据传输和魔术function,但不启用对我们想象设备的过滤。 为此,我们必须只有#0和#2位设置( 1 ),而#1位未设置( 0 )。 这就是当Bitwise OR运算符和我们的预定义掩码一起使用时。 我们做的是这样的:

 uint32_t value_for_device = MYDEV_ENABLE_DATA_FLOW | MYDEV_ENABLE_MAGIC; 

其中“OR”为0b0010b100 ,给出0b101值。 我们将其发送到设备,它会检查每一位并启用或禁用相应的function。

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

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

当然,这不是唯一的用法。 有很多有用的例子,请参阅Sean Eron Anderson的“Bit Twiddling Hacks” 。

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

可维护性

容易改变周围的事物

它可以更容易地改变现状。 只更改移位宽度而不是继续添加/删除'<更容易更改周围的事物

表达意图

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

灵活性

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

 #define MY_BIT (1u< 

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

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

希望它能稍微清理一下 。 祝好运!

是的。 也许它在设置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) { /* ... */ } 

通常这样做是为了表明定义代表一个位标志。 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和BAR)调用该函数,并检查返回以查看是否设置了位2 (BAZ)。