define SOMETHING (1 << 0)

I came accros this line of code:

#define CPARSER_FLAGS_DEBUG        (1 << 0)

What does it do? Its the same as:

#define CPARSER_FLAGS_DEBUG        (1)

Right?


In C-inspired languages, << and >> operators are left and right bitwise shift operators (though in C++ they can be overloaded — the most famous overload is probably I/O stream operators). For example,

x = y << 2;

assigns x the result of shifting y to the left by two bits.

Usually you will see a lot of byte shifting in low-level code and here is why... Any hardware provides a way to configure and control its behavior but nobody wants to use the whole integer to represent, say, ON/OFF state. Therefore, hardware developers generally provide a single integer (aka a register, most often unsigned 32-bit) and state that, for example, bit #0 enables or disables data transmission, bit #1 enables or disables data filtering, bit #3 does some other magic and so one and so force. Generally, one or more settings can be read or changed at the same time. Now imagine how convenient that is for software developers — instead of working with simple integers (or booleans), programmers have to deal with bits that are generally not addressable by the CPU. To simplify their lives, developers define masks. Sticking with the above example, the configuration masks could look like this:

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

Since the right hand side of the shift expression is known, compiler will generate the following integers for each value respectively:

  • 1
  • 2
  • 4
  • Which at first might not make a lot of sense, but if you look at those values in binary representation, the look like this:

  • 0b001
  • 0b010
  • 0b100
  • In other words, each value has only one bit set at different positions. Then, say we want to enable data transmission and a magic functionality but not enable filtering for our imaginary device. For that, we would have to have only bits #0 and #2 set ( 1 ), and bit #1 unset ( 0 ). This is when Bitwise OR operator along with our pre-defined masks come handy. What we do is this:

    uint32_t value_for_device = MYDEV_ENABLE_DATA_FLOW | MYDEV_ENABLE_MAGIC;
    

    Which "OR"s 0b001 and 0b100 , giving 0b101 value. We send this to a device, it checks every bit and enables or disables corresponding functionality.

    Other bits operations are often used as well. Say, we don't know what is currently enabled or disabled, and we don't want to change anything but just make sure that data filtering is off. This can be done by reading the current configuration, un-setting the bit, and writing it back. For example:

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

    This is, of course, not the only usage. For a lot of useful examples, see "Bit Twiddling Hacks" by Sean Eron Anderson.

    OK, getting back to your original question — why write (1<<0) and not simply (1) ? There are a number of reasons:

    Consistency

    It is more consistent to have something like this:

    #define A (1<<0)
    #define B (1<<1)
    #define C (1<<2)
    

    Rather than this:

    #define A (1)
    #define B (1<<1)
    #define C (1<<2)
    

    Or even this:

    #define A 1
    #define B 2
    #define C 4
    

    Maintainability

    Easy to change things around

    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 '<

    Expression of intent

    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.

    Flexibility

    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!


    Yes, it is. Maybe it is used for symmetry when setting values for flags:

    #define FLAG_1  (1 << 0)
    #define FLAG_2  (1 << 2)
    #define FLAG_3  (1 << 3)
    /* ... */
    

    Don't worry about performances, a good compiler will be able to optimize such operations.

    You can combine these values as follow:

    /* Flags FLAG_1, FLAG_2 and FLAG_3 are set. */
    f = FLAG_1 | FLAG_2 | FLAG_3;
    

    And testing whether a given flag is set:

    /* True if FLAG_1 is set. */
    if (f & FLAG_1) { /* ... */ }
    

    This is usually done to show that the definition represents a bit flag. Esp. when there are multiple flags defined together. In this case the magnitude of the shift defines the bit position that the definition represents. Defining it like that also makes things line up nicely:

    #define FOO_FLAG (1 << 0)
    #define BAR_FLAG (1 << 1)
    #define BAZ_FLAG (1 << 2)
    

    This can then be used when calling a function that expects a series of flags like so:

    int ret = some_function(FOO_FLAG | BAR_FLAG) & BAZ_FLAG;
    

    This then calls the function with bits 0 and 1 (FOO & BAR) and checks the return to see if bit 2 (BAZ) was set.

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

    上一篇: 这个声明的含义是什么?

    下一篇: 定义SOMETHING(1 << 0)