定义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时
  • 换句话说,每个值只有一个位设置在不同的位置。 然后,假设我们想要启用数据传输和魔术功能,但不启用我们假想设备的过滤功能。 为此,我们必须仅将位#0和#2设置为( 1 ),并将位#1设置为( 0 )。 这是当我们的预定义的掩码方便的时候,按位或运算符。 我们做的是这样的:

    uint32_t value_for_device = MYDEV_ENABLE_DATA_FLOW | MYDEV_ENABLE_MAGIC;
    

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

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

    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<<MAGIC_BIT_OFFSET)
    

    然后,你不知道结果是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) { /* ... */ }
    

    这通常是为了显示定义代表一个位标志。 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)。

    链接地址: http://www.djcxy.com/p/72481.html

    上一篇: define SOMETHING (1 << 0)

    下一篇: DRYing up JavaScript functions taking optional arguments and a callback