Binary literals?

Viewed 88784

In code, I sometimes see people specify constants in hex format like this:

const int has_nukes        = 0x0001;
const int has_bio_weapons  = 0x0002;
const int has_chem_weapons = 0x0004;
// ...
int arsenal = has_nukes | has_bio_weapons | has_chem_weapons; // all of them
if(arsenal &= has_bio_weapons){
  std::cout << "BIO!!"
}

But it doesn't make sense to me to use the hex format here. Is there a way to do it directly in binary? Something like this:

const int has_nukes        = 0b00000000000000000000000000000001;
const int has_bio_weapons  = 0b00000000000000000000000000000010;
const int has_chem_weapons = 0b00000000000000000000000000000100;
// ...

I know the C/C++ compilers won't compile this, but there must be a workaround? Is it possible in other languages like Java?

19 Answers

I'd use a bit shift operator:

const int has_nukes        = 1<<0;
const int has_bio_weapons  = 1<<1;
const int has_chem_weapons = 1<<2;
// ...
int dangerous_mask = has_nukes | has_bio_weapons | has_chem_weapons;
bool is_dangerous = (country->flags & dangerous_mask) == dangerous_mask;

It is even better than flood of 0's.

By the way, the next C++ version will support user defined literals. They are already included into the working draft. This allows that sort of stuff (let's hope i don't have too many errors in it):

template<char... digits>
constexpr int operator "" _b() {
    return conv2bin<digits...>::value;
}

int main() {
    int const v = 110110110_b;
}

conv2bin would be a template like this:

template<char... digits>
struct conv2bin;

template<char high, char... digits>
struct conv2bin<high, digits...> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0') * (1 << sizeof...(digits)) + 
                             conv2bin<digits...>::value;
};

template<char high>
struct conv2bin<high> {
    static_assert(high == '0' || high == '1', "no bin num!");
    static int const value = (high - '0');
};

Well, what we get are binary literals that evaluate fully at compile time already, because of the "constexpr" above. The above uses a hard-coded int return type. I think one could even make it depend on the length of the binary string. It's using the following features, for anyone interested:

Actually, current GCC trunk already implements variadic templates and static assertions. Let's hope it will support the other two soon. I think C++1x will rock the house.

The C++ Standard Library is your friend:

#include <bitset>

const std::bitset <32> has_nukes( "00000000000000000000000000000001" );

GCC supports binary constants as an extension since 4.3. See the announcement (look at the section "New Languages and Language specific improvements").

You can use << if you like.

int hasNukes = 1;
int hasBioWeapons = 1 << 1;
int hasChemWeapons = 1 << 2;

This discussion may be interesting... Might have been, as the link is dead unfortunately. It described a template based approach similar to other answers here.

And also there is a thing called BOOST_BINARY.

The term you want is binary literals

Ruby has them with the syntax you give.

One alternative is to define helper macros to convert for you. I found the following code at http://bytes.com/groups/c/219656-literal-binary

/* Binary constant generator macro
 * By Tom Torfs - donated to the public domain
 */

/* All macro's evaluate to compile-time constants */

/* *** helper macros *** */

/* turn a numeric literal into a hex constant
 * (avoids problems with leading zeroes)
 * 8-bit constants max value 0x11111111, always fits in unsigned long
 */
#define HEX_(n) 0x##n##LU

/* 8-bit conversion function */
#define B8_(x) ((x & 0x0000000FLU) ?   1:0) \
             | ((x & 0x000000F0LU) ?   2:0) \
             | ((x & 0x00000F00LU) ?   4:0) \
             | ((x & 0x0000F000LU) ?   8:0) \
             | ((x & 0x000F0000LU) ?  16:0) \
             | ((x & 0x00F00000LU) ?  32:0) \
             | ((x & 0x0F000000LU) ?  64:0) \
             | ((x & 0xF0000000LU) ? 128:0)

/* *** user macros *** /

/* for upto 8-bit binary constants */
#define B8(d) ((unsigned char) B8_(HEX_(d)))

/* for upto 16-bit binary constants, MSB first */
#define B16(dmsb, dlsb) (((unsigned short) B8(dmsb) << 8) \
                                         | B8(dlsb))

/* for upto 32-bit binary constants, MSB first */
#define B32(dmsb, db2, db3, dlsb) (((unsigned long) B8(dmsb) << 24) \
                                 | ((unsigned long) B8( db2) << 16) \
                                 | ((unsigned long) B8( db3) <<  8) \
                                 |                  B8(dlsb))

/* Sample usage:
 * B8(01010101) = 85
 * B16(10101010,01010101) = 43605
 * B32(10000000,11111111,10101010,01010101) = 2164238933
 */

The next version of C++, C++0x, will introduce user defined literals. I'm not sure if binary numbers will be part of the standard but at the worst you'll be able to enable it yourself:

int operator "" _B(int i);

assert( 1010_B == 10);

I write binary literals like this:

const int has_nukes        = 0x0001;
const int has_bio_weapons  = 0x0002;
const int has_chem_weapons = 0x0004;

It's more compact than your suggested notation, and easier to read. For example:

const int upper_bit = 0b0001000000000000000;

versus:

const int upper_bit = 0x04000;

Did you notice that the binary version wasn't an even multiple of 4 bits? Did you think it was 0x10000?

With a little practice hex or octal are easier for a human than binary. And, in my opinion, easier to read that using shift operators. But I'll concede that my years of assembly language work may bias me on that point.

Java doesn't support binary literals either, unfortunately. However, it has enums which can be used with an EnumSet. An EnumSet represents enum values internally with bit fields, and presents a Set interface for manipulating these flags.

Alternatively, you could use bit offsets (in decimal) when defining your values:

const int HAS_NUKES        = 0x1 << 0;
const int HAS_BIO_WEAPONS  = 0x1 << 1;
const int HAS_CHEM_WEAPONS = 0x1 << 2;

There's no syntax for literal binary constants in C++ the way there is for hexadecimal and octal. The closest thing for what it looks like you're trying to do would probably be to learn and use bitset.

One, slightly horrible way you could do it is by generating a .h file with lots of #defines...

#define b00000000 0
#define b00000001 1
#define b00000010 2
#define b00000011 3
#define b00000100 4

etc. This might make sense for 8-bit numbers, but probably not for 16-bit or larger.

Alternatively, do this (similar to Zach Scrivena's answer):

#define bit(x) (1<<x)
int HAS_NUKES       = bit(HAS_NUKES_OFFSET);
int HAS_BIO_WEAPONS = bit(HAS_BIO_WEAPONS_OFFSET);

As an aside:

Especially if you're dealing with a large set, instead of going through the [minor] mental effort of writing a sequence of shift amounts, you can make each constant depend on the previously defined constant:

const int has_nukes        = 1;
const int has_bio_weapons  = has_nukes        << 1;
const int has_chem_weapons = has_bio_weapons  << 1;
const int has_nunchuks     = has_chem_weapons << 1;
// ...

Looks a bit redundant, but it's less typo-prone. Also, you can simply insert a new constant in the middle without having to touch any other line except the one immediately following it:

const int has_nukes        = 1;
const int has_gravity_gun  = has_nukes        << 1; // added
const int has_bio_weapons  = has_gravity_gun  << 1; // changed
const int has_chem_weapons = has_bio_weapons  << 1; // unaffected from here on
const int has_nunchuks     = has_chem_weapons << 1;
// ...

Compare to:

const int has_nukes        = 1 << 0;
const int has_bio_weapons  = 1 << 1;
const int has_chem_weapons = 1 << 2;
const int has_nunchuks     = 1 << 3;
// ...
const int has_scimatar     = 1 << 28;
const int has_rapier       = 1 << 28; // good luck spotting this typo!
const int has_katana       = 1 << 30;

And:

const int has_nukes        = 1 << 0;
const int has_gravity_gun  = 1 << 1;  // added
const int has_bio_weapons  = 1 << 2;  // changed
const int has_chem_weapons = 1 << 3;  // changed
const int has_nunchuks     = 1 << 4;  // changed
// ...                                // changed all the way
const int has_scimatar     = 1 << 29; // changed *sigh*
const int has_rapier       = 1 << 30; // changed *sigh* 
const int has_katana       = 1 << 31; // changed *sigh*

As an aside to my aside, it's probably equally hard to spot a typo like this:

const int has_nukes        = 1;
const int has_gravity_gun  = has_nukes        << 1;
const int has_bio_weapons  = has_gravity_gun  << 1;
const int has_chem_weapons = has_gravity_gun  << 1; // oops!
const int has_nunchuks     = has_chem_weapons << 1;

So, I think the main advantage of this cascading syntax is when dealing with insertions and deletions of constants.

Another method:

template<unsigned int N>
class b
{
public:
    static unsigned int const x = N;

    typedef b_<0>  _0000;
    typedef b_<1>  _0001;
    typedef b_<2>  _0010;
    typedef b_<3>  _0011;
    typedef b_<4>  _0100;
    typedef b_<5>  _0101;
    typedef b_<6>  _0110;
    typedef b_<7>  _0111;
    typedef b_<8>  _1000;
    typedef b_<9>  _1001;
    typedef b_<10> _1010;
    typedef b_<11> _1011;
    typedef b_<12> _1100;
    typedef b_<13> _1101;
    typedef b_<14> _1110;
    typedef b_<15> _1111;

private:
    template<unsigned int N2>
    struct b_: public b<N << 4 | N2> {};
};

typedef b<0>  _0000;
typedef b<1>  _0001;
typedef b<2>  _0010;
typedef b<3>  _0011;
typedef b<4>  _0100;
typedef b<5>  _0101;
typedef b<6>  _0110;
typedef b<7>  _0111;
typedef b<8>  _1000;
typedef b<9>  _1001;
typedef b<10> _1010;
typedef b<11> _1011;
typedef b<12> _1100;
typedef b<13> _1101;
typedef b<14> _1110;
typedef b<15> _1111;

Usage:

std::cout << _1101::_1001::_1101::_1101::x;

Implemented in CityLizard++ (citylizard/binary/b.hpp).

Binary literals are part of the C++ language since C++14. It’s literals that start with 0b or 0B. Reference

Maybe less relevant to binary literals, but this just looks as if it can be solved better with a bit field.

struct DangerCollection : uint32_t {
  bool has_nukes : 1;
  bool has_bio_weapons : 1;
  bool has_chem_weapons : 1;
  // .....
};
DangerCollection arsenal{
  .has_nukes = true,
  .has_bio_weapons = true,
  .has_chem_weapons = true,
// ...
};
if(arsenal.has_bio_weapons){
  std::cout << "BIO!!"
}

You would still be able to fill it with binary data, since its binary footprint is just a uint32. This is often used in combination with a union, for compact binary serialisation:

union DangerCollectionUnion {
  DangerCollection collection;
  uint8_t data[sizeof(DangerCollection)];
};
DangerCollectionUnion dc;
std::memcpy(dc.data, bitsIGotFromSomewhere, sizeof(DangerCollection));
if (dc.collection.has_bio_weapons) {
  // ....

In my experience less error prone and easy to understand what's going on.

Related