135

I want to extract bits of a decimal number.

For example, 7 is binary 0111, and I want to get 0 1 1 1 all bits stored in bool. How can I do so?

OK, a loop is not a good option, can I do something else for this?

9 Answers 9

209

If you want the k-th bit of n, then do

(n & ( 1 << k )) >> k 

Here we create a mask, apply the mask to n, and then right shift the masked value to get just the bit we want. We could write it out more fully as:

 int mask = 1 << k; int masked_n = n & mask; int thebit = masked_n >> k; 

You can read more about bit-masking here.

Here is a program:

#include <stdio.h> #include <stdlib.h> int *get_bits(int n, int bitswanted){ int *bits = malloc(sizeof(int) * bitswanted); int k; for(k=0; k<bitswanted; k++){ int mask = 1 << k; int masked_n = n & mask; int thebit = masked_n >> k; bits[k] = thebit; } return bits; } int main(){ int n=7; int bitswanted = 5; int *bits = get_bits(n, bitswanted); printf("%d = ", n); int i; for(i=bitswanted-1; i>=0;i--){ printf("%d ", bits[i]); } printf("\n"); } 
Sign up to request clarification or add additional context in comments.

6 Comments

(n >> k) & 1 is equally valid and does not require computing the mask as the mask is constant due to shifting before masking instead of the other way around.
@Joe can you explain that, perhaps in an answer, please?
@Yar extended my comment a little and added a new answer as requested
When using known bits for information (i.e. for network protocols, such as Websockets), casting the data onto a struct can be useful too, as you get all the required data with a single operation.
@forefinger, can you please post an example output of the code.
|
110

As requested, I decided to extend my comment on forefinger's answer to a full-fledged answer. Although his answer is correct, it is needlessly complex. Furthermore all current answers use signed ints to represent the values. This is dangerous, as right-shifting of negative values is implementation-defined (i.e. not portable) and left-shifting can lead to undefined behavior (see this question).

By right-shifting the desired bit into the least significant bit position, masking can be done with 1. No need to compute a new mask value for each bit.

(n >> k) & 1 

As a complete program, computing (and subsequently printing) an array of single bit values:

#include <stdio.h> #include <stdlib.h> int main(void) { unsigned input = 0b0111u, n_bits = 4u, *bits = malloc(sizeof *bits * n_bits), bit = 0; if (!bits) { return EXIT_FAILURE; } for (bit = 0; bit < n_bits; ++bit) { bits[bit] = (input >> bit) & 1; } for (bit = n_bits; bit--; ) { printf("%u", bits[bit]); } printf("\n"); free(bits); } 

Assuming that you want to calculate all bits as in this case, and not a specific one, the loop can be further changed to

for(bit = 0; bit < n_bits; ++bit, input >>= 1) { bits[bit] = input & 1; } 

This modifies input in place and thereby allows the use of a constant width, single-bit shift, which may be more efficient on some architectures.

Comments

16

Here's one way to do it—there are many others:

bool b[4]; int v = 7; // number to dissect for (int j = 0; j < 4; ++j) b [j] = 0 != (v & (1 << j)); 

It is hard to understand why use of a loop is not desired, but it is easy enough to unroll the loop:

bool b[4]; int v = 7; // number to dissect b [0] = 0 != (v & (1 << 0)); b [1] = 0 != (v & (1 << 1)); b [2] = 0 != (v & (1 << 2)); b [3] = 0 != (v & (1 << 3)); 

Or evaluating constant expressions in the last four statements:

b [0] = 0 != (v & 1); b [1] = 0 != (v & 2); b [2] = 0 != (v & 4); b [3] = 0 != (v & 8); 

Comments

3

Here's a very simple way to do it;

int main() { int s=7,l=1; vector <bool> v; v.clear(); while (l <= 4) { v.push_back(s%2); s /= 2; l++; } for (l=(v.size()-1); l >= 0; l--) { cout<<v[l]<<" "; } return 0; } 

Comments

2

If you don't want any loops, you'll have to write it out:

#include <stdio.h> #include <stdbool.h> int main(void) { int num = 7; #if 0 bool arr[4] = { (num&1) ?true: false, (num&2) ?true: false, (num&4) ?true: false, (num&8) ?true: false }; #else #define BTB(v,i) ((v) & (1u << (i))) ? true : false bool arr[4] = { BTB(num,0), BTB(num,1), BTB(num,2), BTB(num,3)}; #undef BTB #endif printf("%d %d %d %d\n", arr[3], arr[2], arr[1], arr[0]); return 0; } 

As demonstrated here, this also works in an initializer.

Comments

1

@prateek thank you for your help. I rewrote the function with comments for use in a program. Increase 8 for more bits (up to 32 for an integer).

std::vector <bool> bits_from_int (int integer) // discern which bits of PLC codes are true { std::vector <bool> bool_bits; // continously divide the integer by 2, if there is no remainder, the bit is 1, else it's 0 for (int i = 0; i < 8; i++) { bool_bits.push_back (integer%2); // remainder of dividing by 2 integer /= 2; // integer equals itself divided by 2 } return bool_bits; } 

Comments

0
#include <stdio.h> int main(void) { int number = 7; /* signed */ int vbool[8 * sizeof(int)]; int i; for (i = 0; i < 8 * sizeof(int); i++) { vbool[i] = number<<i < 0; printf("%d", vbool[i]); } return 0; } 

Comments

0

If I could rephrase the question, a more general request to extract a set of bits from an integer could be stated as:

I want to extract "size" number of bits from a decimal number "n" from "pos" bit onwards so that I get the bits starting from bit positions "pos + size" to "pos"

The more general statement above can then be stated as:

I want to extract 1 bit from a decimal number "n' from bit position "pos"

You can then change the above statement to:

I want to extract the bits of a from a decimal number "n" one bit at a time and store it into a boolean array so that the bit position "pos" corresponds to the array index "pos".

Assuming that the first "position" of the bit in the decimal number is the LSB i.e bit 0, we can extract n bits from a decimal number like this:

create mask for number of bits : (1 << size) - 1
shift the number by number of bits so that the bit at index is now the LSB : n >> pos
Logical AND the shifted value with the mask : (n >> pos) & ((1 << size) - 1)

Here is an example:

#define GET_N_BITS(n, size, pos, ret) ({ \ ret = (n >> pos) & ((1 << size) - 1); \ )} main() { int n = 7; int extracted_bits = 0; // extract 2 bits from bit 1 onwards from decimal number 7 GET_N_BITS(n, 2, 1, extracted_bits); // extracted bits = b0011 = 3 } 

We can then change the above to extract and return one bit from a given bit position and store it in an array.

#define GET_NTH_BIT(n, pos) ({ \ bool ret; \ ret = (n >> pos) & 1 \ ret; \ }) main() { int n = 7, i = 0; bool n_bit_by_bit[32]; for (i = 0 ; i < 32 ; i++) n_bit_by_bit[i] = GET_NTH_BIT(n, i); } 

Comments

0

You say that you don't want a loop. However, you can write a loop in your source, and a decent compiler will be able to unroll that loop when the number of bits to convert is fixed.

For example, consider this conversion function:

/* Store the COUNT least-signfificant bits of VALUE into DEST */ void to_bits(unsigned value, int count, bool dest[count]) { bool *d = dest; while (count--) { *d++ = value & (1u << count); } } 

This contains a loop of unknown bound, so will compile to a machine-language loop. But we can show what happens when we ask to convert a specific number of bits, by calling it from another function:

void to_bits_4(unsigned value, bool dest[4]) { to_bits(value, 4, dest); } 

If we examine this code on Compiler Explorer, we see that GCC converts it to pure linear code - e.g. for x86:

to_bits_4: movq %rsi, %r8 movl %edi, %eax movl %edi, %esi movl %edi, %ecx shrl %esi andl $1, %eax shrl $2, %ecx movl %edi, %edx sall $8, %eax andl $1, %esi andl $1, %ecx shrl $3, %edx orl %esi, %eax andl $1, %edx sall $8, %eax orl %ecx, %eax sall $8, %eax orl %edx, %eax movl %eax, (%r8) ret 

Note that your compiler is smarter than you are, and is able to use SIMD instructions where available. For example:

void to_bits_16(unsigned value, bool dest[16]) { to_bits(value, 16, dest); } 

On x86-64, this becomes:

to_bits_16: vmovd %edi, %xmm6 vpxor %xmm3, %xmm3, %xmm3 vpcmpeqd %xmm5, %xmm5, %xmm5 vpbroadcastd %xmm6, %xmm1 vpsrld $31, %xmm5, %xmm5 vpxor %xmm4, %xmm4, %xmm4 vpand .LC0(%rip), %xmm1, %xmm0 vpand .LC2(%rip), %xmm1, %xmm2 vpcmpeqd %xmm3, %xmm0, %xmm0 vpcmpeqd %xmm3, %xmm2, %xmm2 vpcmpeqd %xmm3, %xmm0, %xmm0 vpcmpeqd %xmm3, %xmm2, %xmm2 vpand %xmm5, %xmm0, %xmm0 vpand %xmm5, %xmm2, %xmm2 vpblendw $85, %xmm2, %xmm4, %xmm2 vpblendw $85, %xmm0, %xmm4, %xmm0 vpackusdw %xmm2, %xmm0, %xmm0 vpand .LC3(%rip), %xmm1, %xmm2 vpand .LC4(%rip), %xmm1, %xmm1 vpcmpeqd %xmm3, %xmm2, %xmm2 vpcmpeqd %xmm3, %xmm1, %xmm1 vpcmpeqd %xmm3, %xmm2, %xmm2 vpcmpeqd %xmm3, %xmm1, %xmm1 vpand %xmm5, %xmm2, %xmm2 vpand %xmm5, %xmm1, %xmm1 vpblendw $85, %xmm2, %xmm4, %xmm2 vpblendw $85, %xmm1, %xmm4, %xmm4 vpackusdw %xmm4, %xmm2, %xmm1 vpcmpeqd %xmm2, %xmm2, %xmm2 vpsrlw $8, %xmm2, %xmm2 vpand %xmm0, %xmm2, %xmm0 vpand %xmm1, %xmm2, %xmm2 vpackuswb %xmm2, %xmm0, %xmm0 vmovdqu %xmm0, (%rsi) ret .LC0: .long 32768 .long 16384 .long 8192 .long 4096 .LC2: .long 2048 .long 1024 .long 512 .long 256 .LC3: .long 128 .long 64 .long 32 .long 16 .LC4: .long 8 .long 4 .long 2 .long 1 

And on AArch64:

to_bits_16: dup v31.4s, w0 adrp x0, .LC0 ldr q0, [x0, #:lo12:.LC0] adrp x0, .LC1 ldr q29, [x0, #:lo12:.LC1] adrp x0, .LC2 cmtst v0.4s, v31.4s, v0.4s ldr q28, [x0, #:lo12:.LC2] adrp x0, .LC3 cmtst v29.4s, v31.4s, v29.4s ldr q30, [x0, #:lo12:.LC3] cmtst v28.4s, v31.4s, v28.4s and z0.s, z0.s, 1 cmtst v30.4s, v31.4s, v30.4s and z29.s, z29.s, 1 and z28.s, z28.s, 1 and z30.s, z30.s, 1 uzp1 v29.8h, v0.8h, v29.8h uzp1 v30.8h, v28.8h, v30.8h uzp1 v30.16b, v29.16b, v30.16b str q30, [x1] ret .LC0: .word 32768 .word 16384 .word 8192 .word 4096 .LC1: .word 2048 .word 1024 .word 512 .word 256 .LC2: .word 128 .word 64 .word 32 .word 16 .LC3: .word 8 .word 4 .word 2 .word 1 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.