2

Is it possible in C++ to define BIT0, BIT1, BIT2 in another way in C++ without using #define?

#define BIT0 0x00000001
#define BIT1 0x00000002
#define BIT2 0x00000004

I then take the same thing and make states out of those bits:

#define MOTOR_UP   BIT0
#define MOTOR_DOWN BIT1

Note: I am using 32 bits only, not 64 bits. I am also using a setBit(flagVariable, BIT) (consequently a clrBit macro to do the opposite) macro to set the bits then compare whether the bit is set using the bitwise operator such as

if (flagVariable & MOTOR_UP) { 
   // do something
   clrBit(flagVariable, MOTOR_UP);
}

Is there a type in C++ that already contains these bit masks?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
  • 1
    I'm curious about your numbering scheme - I understand Bit0 being the least significant bit, but why is Bit1 the 3rd least significant bit, and Bit2 the 4th? Either you're missing 0x00000002 or you have a very inconsistent and confusing practice. – Eclipse Jul 08 '10 at 01:09
  • I am curious at why this is defined with macros. It's very bad practice to use `#define` for constants in C++ code. – Matthieu M. Jul 08 '10 at 06:34
  • setBit is a macro which sets the bit and clrBit clears the bit. The code was ported from C a long time ago. –  Jul 08 '10 at 11:07

9 Answers9

7

You could use an enum instead:

enum {
  BIT1 = 1,
  BIT2 = 2,
  BIT3 = 4,
  ...
};
Georg Fritzsche
  • 97,545
  • 26
  • 194
  • 236
Staffan
  • 1,769
  • 13
  • 15
  • 9
    *§7.2/4* says: *"It is implementation-defined which integral type is used as the underlying type for an enumeration except that the underlying type shall not be larger than `int` unless the value of an enumerator cannot fit in an `int` or `unsigned int`."* – Georg Fritzsche Jul 08 '10 at 00:10
  • I removed that note now. Don't forget that you can always *edit* your answer to fix invalid facts. – Georg Fritzsche Jul 09 '10 at 01:43
6

You could use a function instead:

#define BIT(n) (1<<(n))

*edited for Macro Monster compliance

tzaman
  • 46,925
  • 11
  • 90
  • 115
6

Here's one way:

const int bit0 = (1<<0);
const int bit1 = (1<<1);
const int bit2 = (1<<2);
//...

const int motor_up = bit0;
const int motor_down = bit1;
In silico
  • 51,091
  • 10
  • 150
  • 143
6

How about:

enum Bits
{
    BIT0    = 0x00000001,
    BIT1    = 0x00000004,
    BIT2    = 0x00000008,

    MOTOR_UP    = BIT0,
    MOTOR_DOWN  = BIT1
};
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • So BIT0 is turned into an `int` as per the C++ spec for enums? –  Jul 08 '10 at 12:39
  • 1
    Its not turned into an int. It is represented on the system as an int. But that should not really make any difference to you. The integral promotion rules will convert it to the correct type depending on the usage context. – Martin York Jul 08 '10 at 13:24
  • 1
    `BIT0` is actually an `int` inside the `{}`, and an `Bits` value outside. – MSalters Jul 08 '10 at 13:39
  • @Martin: Is there an advantage to declaring MOTOR_UP or MOTOR_DOWN inside the enum? –  Jul 12 '10 at 17:18
  • @Changeling: It keeps all the bit flags in one place thus makes maintainableity easier. – Martin York Jul 12 '10 at 18:11
  • @Martin: Is there a limit to the number of `enum` elements? I have a lot more than two. –  Jul 12 '10 at 18:18
  • @Changeling: Thats a new question unto itself (you should probably ask on the forum). I believe (but don't have a reference) that technically there is a minimum number that the compiler must support (65536) though in modern compilers the actual number is probably on limited by your machines memory (but this is a guess). – Martin York Jul 12 '10 at 18:30
6

How about using a template?

template <int BitN>
struct bit
{
    static const int value = (1 << BitN);
}

You would use it thus:

const int MOTOR_UP   = bit<0>::value;
const int MOTOR_DOWN = bit<1>::value;

Or with an enum:

enum
{
    MOTOR_UP   = bit<0>::value,
    MOTOR_DOWN = bit<1>::value
}
Cogwheel
  • 22,781
  • 4
  • 49
  • 67
  • The value is available at compile time so there's no reason why the enum wouldn't work. – Grant Peters Jul 08 '10 at 05:31
  • @Grant Peters: I'm overly cautious when I answer questions without access to a compiler ;) – Cogwheel Jul 08 '10 at 13:49
  • 1
    Well, what's the point? bit::value isn't more expressive than (1< – peterchen Jul 08 '10 at 13:55
  • @peterchen: that's more applicable to the original question than it is to my answer (and it's equally applicable to most of the other answers here). That being said, I disagree with the assertion that it isn't any more expressive than the raw expression. Just the presence of the word "bit" makes it marginally more understandable to someone less-than-familiar with bit shift operations. – Cogwheel Jul 08 '10 at 14:03
  • I agree that it's a valid replacement - a bit overblown, though (pardon the pun). I just wondered why one would pick that over an enum. -- regarding obviousness, I'd expect most working with hardware to pick up on the "1< – peterchen Jul 08 '10 at 14:10
  • The advantage over the enum is that you don't need a different definition of BIT[whatever] for every single bit position. A single template (you could fit on one line if you wanted) encapsulates the entire set of possible flags. Besides, templates are cool ;) Really, this is just a template version of `#define BIT(n) (1 << (n))` – Cogwheel Jul 08 '10 at 14:46
  • Can I reuse your bit template in a commercial project (the 5 lines of code of your first code snippet)? – Vertexwahn Sep 26 '16 at 10:19
  • 1
    @Vertexwahn Sure thing! Edit: I release this code to anyone for any use with no warranty. – Cogwheel Sep 26 '16 at 18:56
2

I say combine tzaman's and Martin York's answers:

#define BIT(x) (1 << (x))

enum {
    motor_up = BIT(0),
    motor_down = BIT(1)
};

There's no particular reason for a bunch of macros or enums with silly-names like BIT0, BIT1, ..., BITn.

And enums work great as integral constants - they don't have macro global-namespace-stomping powers and they work equally well in C and C++ (which isn't true for const int types).

Community
  • 1
  • 1
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
0

You probably want something like the STL's std::bitset.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • bitset is a bad way to go. you can not give symbolic names to the individual bit fields. – jyoung Jul 08 '10 at 00:18
  • 1
    @JYoung: You can't give symbolic names to half the other answers here either. At least with `bitset` you're not manually twiddling bits. – Billy ONeal Jul 08 '10 at 00:20
0

Use bitfield union and structs. (For Billy: The solution to the problem is C++ code. The sample was using C++/CLI.)

union MotorControl
{
    struct 
    {
        int motorUp :1;
        int motorDown :1;
    };
    struct 
    {
        int all;
    };
};

int main(array<System::String ^> ^args)
{
    MotorControl mc;
    mc.all = 0;
    mc.motorDown = 1;
}
jyoung
  • 5,071
  • 4
  • 30
  • 47
  • 2
    -1 for: That's not C++. Make it C++ and I'll remove my downvote. – Billy ONeal Jul 08 '10 at 00:14
  • Oh -- that's also not portable endian-wise. I'd not downvote for that but thought I'd mention it. – Billy ONeal Jul 08 '10 at 00:16
  • 1
    Do not listen to Billy, this is C++ code. I use this in embedded C++ projects all the time. When you are working with hardware, (like motor control) porting to other endian hardware is usually not an issue. – jyoung Jul 08 '10 at 00:22
  • 1
    @Jyoung: No, that is C++/CLI. C++/CLI is not C++. Your code with the unions and structs is actually correct. `main` is wrong. – Billy ONeal Jul 08 '10 at 00:24
  • 3
    Anonymous structs aren't valid standard C++ either. – Georg Fritzsche Jul 08 '10 at 00:31
  • Does the standard actually guarantee the bits are "packed", i.e. fill up from lowest position to highest? (I dimply remember that not being the case, but that might have been C, or an old standard or whatnot) – peterchen Jul 08 '10 at 13:57
-1

I'd modify Martin's answer just a bit:

enum Bits
{
    BIT0    = 0x00000001,
    BIT1    = BIT0 << 1, 
    BIT2    = BIT1 << 1,

    MOTOR_UP    = BIT0,
    MOTOR_DOWN  = BIT1
};

Using the shift operators makes things a little more consistent, and makes it obvious if you are skip a bit.

Community
  • 1
  • 1
Eclipse
  • 44,851
  • 20
  • 112
  • 171