How to Use a Binary Literal in C or C++

Can I use a binary literal in C or C++?

You can use BOOST_BINARY while waiting for C++0x. :) BOOST_BINARY arguably has an advantage over template implementation insofar as it can be used in C programs as well (it is 100% preprocessor-driven.)

To do the converse (i.e. print out a number in binary form), you can use the non-portable itoa function, or implement your own.

Unfortunately you cannot do base 2 formatting with STL streams (since setbase will only honour bases 8, 10 and 16), but you can use either a std::string version of itoa, or (the more concise, yet marginally less efficient) std::bitset.

#include <boost/utility/binary.hpp>
#include <stdio.h>
#include <stdlib.h>
#include <bitset>
#include <iostream>
#include <iomanip>

using namespace std;

int main() {
unsigned short b = BOOST_BINARY( 10010 );
char buf[sizeof(b)*8+1];
printf("hex: %04x, dec: %u, oct: %06o, bin: %16s\n", b, b, b, itoa(b, buf, 2));
cout << setfill('0') <<
"hex: " << hex << setw(4) << b << ", " <<
"dec: " << dec << b << ", " <<
"oct: " << oct << setw(6) << b << ", " <<
"bin: " << bitset< 16 >(b) << endl;
return 0;
}

produces:

hex: 0012, dec: 18, oct: 000022, bin:            10010
hex: 0012, dec: 18, oct: 000022, bin: 0000000000010010

Also read Herb Sutter's The String Formatters of Manor Farm for an interesting discussion.

Binary literals?

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.

Writing binary number system in C code

Standard C doesn't define binary constants. There's a GNU C extension though (among popular compilers, clang adapts it as well): the 0b or 0B prefixes:

int foo = 0b1010;

If you want to stick with standard C, then there's an option: you can combine a macro and a function to create an almost readable "binary constant" feature:

#define B(x) S_to_binary_(#x)

static inline unsigned long long S_to_binary_(const char *s)
{
unsigned long long i = 0;
while (*s) {
i <<= 1;
i += *s++ - '0';
}
return i;
}

And then you can use it like this:

int foo = B(1010);

If you turn on heavy compiler optimizations, the compiler will most likely eliminate the function call completely (constant folding) or will at least inline it, so this won't even be a performance issue.

Proof:

The following code:

#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <string.h>


#define B(x) S_to_binary_(#x)

static inline unsigned long long S_to_binary_(const char *s)
{
unsigned long long i = 0;
while (*s) {
i <<= 1;
i += *s++ - '0';
}
return i;
}

int main()
{
int foo = B(001100101);

printf("%d\n", foo);

return 0;
}

has been compiled using clang -o baz.S baz.c -Wall -O3 -S, and it produced the following assembly:

    .section    __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main: ## @main
.cfi_startproc
## BB#0:
pushq %rbp
Ltmp2:
.cfi_def_cfa_offset 16
Ltmp3:
.cfi_offset %rbp, -16
movq %rsp, %rbp
Ltmp4:
.cfi_def_cfa_register %rbp
leaq L_.str1(%rip), %rdi
movl $101, %esi ## <= This line!
xorb %al, %al
callq _printf
xorl %eax, %eax
popq %rbp
ret
.cfi_endproc

.section __TEXT,__cstring,cstring_literals
L_.str1: ## @.str1
.asciz "%d\n"


.subsections_via_symbols

So clang completely eliminated the call to the function, and replaced its return value with 101. Neat, huh?

C++ Binary Literal

Binary literals have been a compiler extension in GCC long before C++14 standardized them. You can compile with -pedantic to warn on extensions and -pedantic-errors to elevate those specific warnings to errors:

<source>:3:11: error: binary constants are a C++14 feature or GCC extension
3 | int a = 0b1010; // an error is expected
| ^~~~~~

Separator to make binary literals look cleaner

If you always have the same number of bits (32 in your example) you could #define a macro a bit like this:

#define BITS32(b1,b2,b3,b4,b5,b6,b7,b8) ( \
((b1) << 28) + \
((b2) << 24) + \
((b3) << 20) + \
((b4) << 16) + \
((b5) << 12) + \
((b6) << 8) + \
((b7) << 4) + \
(b8))

and then call it like this:

uint32_t branch_bitmask = BITS32(0b0000,0b1111,0b0000,0b0000,0b0000,0b0000,0b0000,0b0000);

or you can go further and use ## in the macro to prepend the 0b.

But the simple answer for me has always been to use hexadecimal, as one hex digit is 4 bits.

C represent int in base 2

The standard describes no way to create "binary literals". However, the latest versions of GCC and Clang support this feature using a syntax similar to the hex syntax, except it's b instead of x:

int foo = 0b00100101;

As stated, using such binary literals locks you out of Visual Studio's C and C++ compilers, so you may want to take care where and how you use them.

C++14 (I know, I know, this isn't C) standardizes support for binary literals.

What does 0b and 0x stand for when assigning binary and hex?

Any and all integer literals you can create are summarized in the C++ standard by the grammar production at [lex.icon]


integer-literal:
binary-literal integer-suffixopt
octal-literal integer-suffixopt
decimal-literal integer-suffixopt
hexadecimal-literal integer-suffixopt

binary-literal:
0b binary-digit
0B binary-digit
binary-literal 'opt binary-digit

octal-literal:
0
octal-literal 'opt octal-digit

decimal-literal:
nonzero-digit
decimal-literal 'opt digit

hexadecimal-literal:
hexadecimal-prefix hexadecimal-digit-sequence

binary-digit:
0
1

octal-digit: one of
0 1 2 3 4 5 6 7

nonzero-digit: one of
1 2 3 4 5 6 7 8 9

hexadecimal-prefix: one of
0x 0X

hexadecimal-digit-sequence:
hexadecimal-digit
hexadecimal-digit-sequence 'opt hexadecimal-digit

hexadecimal-digit: one of
0 1 2 3 4 5 6 7 8 9
a b c d e f
A B C D E F

As we can deduce from the grammar, there are four types of integer literals:

  • Plain decimal, that must begin with a non-zero digit.
  • Octal, any number with a leading 0 (including a plain 0).
  • Binary, requiring the prefix 0b or 0B.
  • Hexadecimal, requiring the prefix 0x or 0X.

The leading 0 for octal numbers can be thought of as the "O" in "Octal". The other prefixes use a leading zero to mark the beginning of a number that should not be interpreted as decimal. "B" is intuitively for "binary", while "X" is for "hexadecimal".



Related Topics



Leave a reply



Submit