Is there a printf converter to print in binary format?

Viewed 1071608

I can print with printf as a hex or octal number. Is there a format tag to print as binary, or arbitrary base?

I am running gcc.

printf("%d %x %o\n", 10, 10, 10); //prints "10 A 12\n"
print("%b\n", 10); // prints "%b\n"
56 Answers

Here is a quick hack to demonstrate techniques to do what you want.

#include <stdio.h>      /* printf */
#include <string.h>     /* strcat */
#include <stdlib.h>     /* strtol */

const char *byte_to_binary
(
    int x
)
{
    static char b[9];
    b[0] = '\0';

    int z;
    for (z = 128; z > 0; z >>= 1)
    {
        strcat(b, ((x & z) == z) ? "1" : "0");
    }

    return b;
}

int main
(
    void
)
{
    {
        /* binary string to int */

        char *tmp;
        char *b = "0101";

        printf("%d\n", strtol(b, &tmp, 2));
    }

    {
        /* byte to binary string */

        printf("%s\n", byte_to_binary(5));
    }
    
    return 0;
}

There isn't a binary conversion specifier in glibc normally.

It is possible to add custom conversion types to the printf() family of functions in glibc. See register_printf_function for details. You could add a custom %b conversion for your own use, if it simplifies the application code to have it available.

Here is an example of how to implement a custom printf formats in glibc.

You could use a small table to improve speed1. Similar techniques are useful in the embedded world, for example, to invert a byte:

const char *bit_rep[16] = {
    [ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011",
    [ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111",
    [ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011",
    [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111",
};

void print_byte(uint8_t byte)
{
    printf("%s%s", bit_rep[byte >> 4], bit_rep[byte & 0x0F]);
}

1 I'm mostly referring to embedded applications where optimizers are not so aggressive and the speed difference is visible.

Here's a version of the function that does not suffer from reentrancy issues or limits on the size/type of the argument:

#define FMT_BUF_SIZE (CHAR_BIT*sizeof(uintmax_t)+1)

char *binary_fmt(uintmax_t x, char buf[static FMT_BUF_SIZE])
{
    char *s = buf + FMT_BUF_SIZE;
    *--s = 0;
    if (!x) *--s = '0';
    for (; x; x /= 2) *--s = '0' + x%2;
    return s;
}

Note that this code would work just as well for any base between 2 and 10 if you just replace the 2's by the desired base. Usage is:

char tmp[FMT_BUF_SIZE];
printf("%s\n", binary_fmt(x, tmp));

Where x is any integral expression.

Quick and easy solution:

void printbits(my_integer_type x)
{
    for(int i=sizeof(x)<<3; i; i--)
        putchar('0'+((x>>(i-1))&1));
}

Works for any size type and for signed and unsigned ints. The '&1' is needed to handle signed ints as the shift may do sign extension.

There are so many ways of doing this. Here's a super simple one for printing 32 bits or n bits from a signed or unsigned 32 bit type (not putting a negative if signed, just printing the actual bits) and no carriage return. Note that i is decremented before the bit shift:

#define printbits_n(x,n) for (int i=n;i;i--,putchar('0'|(x>>i)&1))
#define printbits_32(x) printbits_n(x,32)

What about returning a string with the bits to store or print later? You either can allocate the memory and return it and the user has to free it, or else you return a static string but it will get clobbered if it's called again, or by another thread. Both methods shown:

char *int_to_bitstring_alloc(int x, int count)
{
    count = count<1 ? sizeof(x)*8 : count;
    char *pstr = malloc(count+1);
    for(int i = 0; i<count; i++)
        pstr[i] = '0' | ((x>>(count-1-i))&1);
    pstr[count]=0;
    return pstr;
}

#define BITSIZEOF(x)    (sizeof(x)*8)

char *int_to_bitstring_static(int x, int count)
{
    static char bitbuf[BITSIZEOF(x)+1];
    count = (count<1 || count>BITSIZEOF(x)) ? BITSIZEOF(x) : count;
    for(int i = 0; i<count; i++)
        bitbuf[i] = '0' | ((x>>(count-1-i))&1);
    bitbuf[count]=0;
    return bitbuf;
}

Call with:

// memory allocated string returned which needs to be freed
char *pstr = int_to_bitstring_alloc(0x97e50ae6, 17);
printf("bits = 0b%s\n", pstr);
free(pstr);

// no free needed but you need to copy the string to save it somewhere else
char *pstr2 = int_to_bitstring_static(0x97e50ae6, 17);
printf("bits = 0b%s\n", pstr2);

As of February 3rd, 2022, the GNU C Library been updated to version 2.35. As a result, %b is now supported to output in binary format.

printf-family functions now support the %b format for output of integers in binary, as specified in draft ISO C2X, and the %B variant of that format recommended by draft ISO C2X.

const char* byte_to_binary(int x)
{
    static char b[sizeof(int)*8+1] = {0};
    int y;
    long long z;

    for (z = 1LL<<sizeof(int)*8-1, y = 0; z > 0; z >>= 1, y++) {
        b[y] = (((x & z) == z) ? '1' : '0');
    }
    b[y] = 0;

    return b;
}

This code should handle your needs up to 64 bits. I created two functions: pBin and pBinFill. Both do the same thing, but pBinFill fills in the leading spaces with the fill character provided by its last argument. The test function generates some test data, then prints it out using the pBinFill function.

#define kDisplayWidth 64

char* pBin(long int x,char *so)
{
  char s[kDisplayWidth+1];
  int i = kDisplayWidth;
  s[i--] = 0x00;  // terminate string
  do {  // fill in array from right to left
    s[i--] = (x & 1) ? '1' : '0';  // determine bit
    x >>= 1;  // shift right 1 bit
  } while (x > 0);
  i++;  // point to last valid character
  sprintf(so, "%s", s+i);  // stick it in the temp string string
  return so;
}

char* pBinFill(long int x, char *so, char fillChar)
{
  // fill in array from right to left
  char s[kDisplayWidth+1];
  int i = kDisplayWidth;
  s[i--] = 0x00;  // terminate string
  do {  // fill in array from right to left
    s[i--] = (x & 1) ? '1' : '0';
    x >>= 1;  // shift right 1 bit
  } while (x > 0);
  while (i >= 0) s[i--] = fillChar;  // fill with fillChar 
  sprintf(so, "%s", s);
  return so;
}

void test()
{
  char so[kDisplayWidth+1];  // working buffer for pBin
  long int val = 1;
  do {
    printf("%ld =\t\t%#lx =\t\t0b%s\n", val, val, pBinFill(val, so, '0'));
    val *= 11;  // generate test data
  } while (val < 100000000);
}

Output:

00000001 =  0x000001 =  0b00000000000000000000000000000001
00000011 =  0x00000b =  0b00000000000000000000000000001011
00000121 =  0x000079 =  0b00000000000000000000000001111001
00001331 =  0x000533 =  0b00000000000000000000010100110011
00014641 =  0x003931 =  0b00000000000000000011100100110001
00161051 =  0x02751b =  0b00000000000000100111010100011011
01771561 =  0x1b0829 =  0b00000000000110110000100000101001
19487171 = 0x12959c3 =  0b00000001001010010101100111000011

There is no formatting function in the C standard library to output binary like that. All the format operations the printf family supports are towards human readable text.

Maybe a bit OT, but if you need this only for debuging to understand or retrace some binary operations you are doing, you might take a look on wcalc (a simple console calculator). With the -b options you get binary output.

e.g.

$ wcalc -b "(256 | 3) & 0xff"
 = 0b11
void
print_binary(unsigned int n)
{
    unsigned int mask = 0;
    /* this grotesque hack creates a bit pattern 1000... */
    /* regardless of the size of an unsigned int */
    mask = ~mask ^ (~mask >> 1);

    for(; mask != 0; mask >>= 1) {
        putchar((n & mask) ? '1' : '0');
    }

}

No standard and portable way.

Some implementations provide itoa(), but it's not going to be in most, and it has a somewhat crummy interface. But the code is behind the link and should let you implement your own formatter pretty easily.

Yet another approach to print in binary: Convert the integer first.

To print 6 in binary, change 6 to 110, then print "110".

Bypasses char buf[] issues.
printf() format specifiers, flags, & fields like "%08lu", "%*lX" still readily usable.
Not only binary (base 2), this method expandable to other bases up to 16.
Limited to smallish integer values.

#include <stdint.h>
#include <stdio.h>
#include <inttypes.h>

unsigned long char_to_bin10(char ch) {
  unsigned char uch = ch;
  unsigned long sum = 0;
  unsigned long power = 1;
  while (uch) {
    if (uch & 1) {
      sum += power;
      }
   power *= 10;
   uch /= 2;
  }
  return sum;
}

uint64_t uint16_to_bin16(uint16_t u) {
  uint64_t sum = 0;
  uint64_t power = 1;
  while (u) {
    if (u & 1) {
      sum += power;
      }
    power *= 16;
    u /= 2;
  }
  return sum;
}

void test(void) {
  printf("%lu\n", char_to_bin10(0xF1));
  // 11110001
  printf("%" PRIX64 "\n", uint16_to_bin16(0xF731));
  // 1111011100110001
}
void DisplayBinary(int n)
{
    int arr[8];
    int top =-1;
    while (n)
    {
        if (n & 1)
            arr[++top] = 1;
        else
            arr[++top] = 0;

        n >>= 1;
    }
    for (int i = top ; i > -1;i--)
    {
        printf("%d",arr[i]);
    }
    printf("\n");
}

Do a function and call it

display_binary(int n)
{
    long int arr[32];
    int arr_counter=0;
    while(n>=1)
    {
        arr[arr_counter++]=n%2;
        n/=2;
    }
    for(int i=arr_counter-1;i>=0;i--)
    {
        printf("%d",arr[i]);
    }
}

My solution returns an int which can then be used in printf. It can also return the bits in big endian or little endian order.

#include <stdio.h>
#include <stdint.h>

int binary(uint8_t i,int bigEndian)
{
    int j=0,m = bigEndian ? 1 : 10000000;
    while (i)
    {
        j+=m*(i%2);
        if (bigEndian) m*=10; else m/=10;
        i >>= 1;
    }
    return j;
}

int main()
{
    char buf[]="ABCDEF";
    printf("\nbig endian = ");
    for (int i=0; i<5; i++) printf("%08d ",binary(buf[i],1));
    printf("\nwee endian = ");
    for (int i=0; i<5; i++) printf("%08d ",binary(buf[i],0));
    getchar();
    return 0;
}

Outputs

big endian = 01000001 01000010 01000011 01000100 01000101 01000110
wee endian = 10000010 01000010 11000010 00100010 10100010 01100010

The combination of functions + macro at the end of this answer can help you.

Use it like that:

float float_var = 9.4;
SHOW_BITS(float_var);

Which will output: Variable 'float_var': 01000001 00010110 01100110 01100110

Note that it is very general and can work with pretty much any type. For instance:

struct {int a; float b; double c;} struct_var = {1,1.1,1.2};
SHOW_BITS(struct_var);

Which will output:

Variable `struct_var`: 00111111 11110011 00110011 00110011 00110011 00110011 00110011 00110011 00111111 10001100 11001100 11001101 00000000 00000000 00000000 00000001

Here's the code:

#define SHOW_BITS(a) ({ \
    printf("Variable `%s`: ", #a);\
    show_bits(&a, sizeof(a));\
})

void show_uchar(unsigned char a)
{
    for(int i = 7; i >= 0; i-= 1) 
        printf("%d", ((a >> i) & 1));
}

void show_bits(void* a, size_t s)
{
    unsigned char* p = (unsigned char*) a;
    for(int i = s-1; i >= 0 ; i -= 1) {
        show_uchar(p[i]);
        printf(" ");
    }
    printf("\n");
}
void print_bits (uintmax_t n)
{
    for (size_t i = 8 * sizeof (int); i-- != 0;)
    {
        char c;
        if ((n & (1UL << i)) != 0)
            c = '1';
        else
            c = '0';

        printf ("%c", c);

    }
}

Not a cover-absolutely-everywhere solution but if you want something quick, and easy to understand, I'm suprised no one has proposed this solution yet.

This is my take on this subject.

Advantages to most other examples:

  1. Uses putchar() which is more efficient than printf() or even (although not as much) puts()
  2. Split into two parts (expected to have code inlined) which allows extra efficiency, if wanted.
  3. Is based on very fast RISC arithmetic operations (that includes not using division and multiplication)

Disadvantages to most examples:

  1. Code is not very straightforward.
  2. print_binary_size() modifies the input variable without a copy.

Note: The best outcome for this code relies on using -O1 or higher in gcc or equivalent.

Here's the code:

    inline void print_binary_sized(unsigned int number, unsigned int digits) {
        static char ZERO = '0';
        int digitsLeft = digits;
        
        do{
            putchar(ZERO + ((number >> digitsLeft) & 1));
        }while(digitsLeft--);
    }

    void print_binary(unsigned int number) {
        int digitsLeft = sizeof(number) * 8;
        
        while((~(number >> digitsLeft) & 1) && digitsLeft){
            digitsLeft--;
        }
        print_binary_sized(number, digitsLeft);
    }
// m specifies how many of the low bits are shown.
// Replace m with sizeof(n) below for all bits and
// remove it from the parameter list if you like.

void print_binary(unsigned long n, unsigned long m) {
    static char show[3] = "01";
    unsigned long mask = 1ULL << (m-1);
    while(mask) {
        putchar(show[!!(n&mask)]); mask >>= 1;
    }
    putchar('\n');
}

Main.c

// Based on https://stackoverflow.com/a/112956/1438550

#include <stdio.h>
#include <stdint.h>

const char *int_to_binary_str(int x, int N_bits){
    static char b[512];
    char *p = b;
    b[0] = '\0';

    for(int i=(N_bits-1); i>=0; i--){
      *p++ = (x & (1<<i)) ? '1' : '0';
      if(!(i%4)) *p++ = ' ';
    }
    return b;
}

int main() {
  for(int i=31; i>=0; i--){
    printf("0x%08X %s \n", (1<<i), int_to_binary_str((1<<i), 32));
  }
  return 0;
}

Expected behavior:

Run:
gcc -pthread -Wformat=0 -lm -o main main.c; ./main

Output:
0x80000000 1000 0000 0000 0000 0000 0000 0000 0000  
0x40000000 0100 0000 0000 0000 0000 0000 0000 0000  
0x20000000 0010 0000 0000 0000 0000 0000 0000 0000  
0x10000000 0001 0000 0000 0000 0000 0000 0000 0000  
0x08000000 0000 1000 0000 0000 0000 0000 0000 0000  
0x04000000 0000 0100 0000 0000 0000 0000 0000 0000  
0x02000000 0000 0010 0000 0000 0000 0000 0000 0000  
0x01000000 0000 0001 0000 0000 0000 0000 0000 0000  
0x00800000 0000 0000 1000 0000 0000 0000 0000 0000  
0x00400000 0000 0000 0100 0000 0000 0000 0000 0000  
0x00200000 0000 0000 0010 0000 0000 0000 0000 0000  
0x00100000 0000 0000 0001 0000 0000 0000 0000 0000  
0x00080000 0000 0000 0000 1000 0000 0000 0000 0000  
0x00040000 0000 0000 0000 0100 0000 0000 0000 0000  
0x00020000 0000 0000 0000 0010 0000 0000 0000 0000  
0x00010000 0000 0000 0000 0001 0000 0000 0000 0000  
0x00008000 0000 0000 0000 0000 1000 0000 0000 0000  
0x00004000 0000 0000 0000 0000 0100 0000 0000 0000  
0x00002000 0000 0000 0000 0000 0010 0000 0000 0000  
0x00001000 0000 0000 0000 0000 0001 0000 0000 0000  
0x00000800 0000 0000 0000 0000 0000 1000 0000 0000  
0x00000400 0000 0000 0000 0000 0000 0100 0000 0000  
0x00000200 0000 0000 0000 0000 0000 0010 0000 0000  
0x00000100 0000 0000 0000 0000 0000 0001 0000 0000  
0x00000080 0000 0000 0000 0000 0000 0000 1000 0000  
0x00000040 0000 0000 0000 0000 0000 0000 0100 0000  
0x00000020 0000 0000 0000 0000 0000 0000 0010 0000  
0x00000010 0000 0000 0000 0000 0000 0000 0001 0000  
0x00000008 0000 0000 0000 0000 0000 0000 0000 1000  
0x00000004 0000 0000 0000 0000 0000 0000 0000 0100  
0x00000002 0000 0000 0000 0000 0000 0000 0000 0010  
0x00000001 0000 0000 0000 0000 0000 0000 0000 0001 

Simple, tested, works for any unsigned integer type. No headaches.

#include <stdint.h>
#include <stdio.h>

// Prints the binary representation of any unsigned integer
// When running, pass 1 to first_call
void printf_binary(unsigned int number, int first_call)
{
        if (first_call)
        {
                printf("The binary representation of %d is [", number);
        }
        if (number >> 1)
        {
                printf_binary(number >> 1, 0);
                putc((number & 1) ? '1' : '0', stdout);
        }
        else 
        {
                putc((number & 1) ? '1' : '0', stdout);
        }
        if (first_call)
        {
                printf("]\n");
        }
}
Related