Home > front end >  How do I print 1 bit in C (not only the least significant bit)?
How do I print 1 bit in C (not only the least significant bit)?

Time:04-10

I am working on a program that sends TCP header (a simulation of the 3-handshaking). I have a variable and this variable contains the data offset (3 bits), reserved (4 bits), and the 9 flags (9 bits). I am using bitwise operations to set the bits. The question is how can I print each of those bits?

  1. Suppose I store the data offset starting on 2 to 4 (left to right): ex. 0111000000000000

How can I print the 3 bits? Variable:

u_int16_t reserved_ofs_flags;

I found this question similar, but the answer only works for the least significant: How do I print one bit?

CodePudding user response:

You can use the bitwise operations to get the bits you want.

For instance:

unsigned int a = 22;           // 10110 in binary
printf("%d\n", a & 1);         // get the bit in the 1's place (0)
printf("%d\n", (a >> 1) & 1);  // get the bit in the 2's place (1)
printf("%d\n", (a >> 2) & 1);  // get the bit in the 4's place (1)
printf("%d\n", (a >> 3) & 1);  // get the bit in the 8's place (0)
printf("%d\n", (a >> 4) & 1);  // get the bit in the 16's place (1)

// 3 in decimal is 11 in binary
printf("%d\n", a & 3);         // get the bits in the 1's and the 2's places
                               // (2 in decimal, 10 in binary)
printf("%d\n", (a >> 1) & 3);  // get the bits in the 2's and the 4's places
                               // (3 in decimal, 11 in binary)

CodePudding user response:

To extract N bits from an unsigned value starting at position P, counting from 0 for the least significant bit, you can use this expression:

unsigned x = (value >> P) & ((1U << (N - 1) << 1) - 1);

Notes:

  • numbering the bits from left to right is a confusing convention. In software, the preferred numbering method is from the least significant bit (number 0) to the most significant bit (number 15 in your example).
  • If N is a compile time constant, the expression ((1U << (N - 1) << 1) - 1) is evaluated at compile time.
  • The expression assumes that N is at least 1 and at most the number of bits in the unsigned type.
  • A simpler expression ((1U << N) - 1) has undefined behavior if N is the number of bits in the unsigned type.
  • For your example P is 12 and N is 3 so you can write: unsigned x = (value >> 12) & 7;

CodePudding user response:

If I understand your question, and you want to be able to extract the value of the N number of bits (from 1 to sizeof(type) * CHAR_BIT) beginning at position P (from 0 to sizeof(type) * CHAR_BIT - 1) then you can extract that subset of bits with:

/** extract N bits from value starting at position P, 
 *  counting from 0 for the least significant bit
 */
unsigned nbitsatp (unsigned value, unsigned N, unsigned P)
{
  /* mask is N 1's bits */
  unsigned mask = ~0u >> ((sizeof mask * CHAR_BIT) - N); 
  
  return (value >> (P - N   1)) & mask;
}

(note: for 4-byte unsigned, N ranges from 1 to 32 while P is zero-based ranging from 0 to 31)

Above, the mask begins with all bits 1 (~0u) and then shifts off the total number of bits minus N (leaving N 1's bits). The value is then shifted by P - N 1 so that you AND the desired number of bits at position P with the corresponding number of 1's bits. Since both are shifted so the values begin at the least significant bit, the result is the value of the N bits at position P.

This avoids having to hardcode the number and individual bit positions for each range of bits you want.

In your example you want to extract the first 3 bits from 0111000000000000 (28672) which would be the 3 bits N == 3 at positon P == 15, the result being 011 (3).

A Short Example

The example below uses unsigned as the type, which so long as it is at least 2-bytes on your hardware will be more than sufficient for uint16_t type.

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

/** extract N bits from value starting at position P, 
 *  counting from 0 for the least significant bit
 */
unsigned nbitsatp (unsigned value, unsigned N, unsigned P)
{
  /* mask is N 1's bits */
  unsigned mask = ~0u >> ((sizeof mask * CHAR_BIT) - N); 
  
  return (value >> (P - N   1)) & mask;
}

int main (void) {

  unsigned v, n, p;
  
  fputs ("enter v, n, p : ", stdout);    /* prompt for v, n, p */
  
  /* read/validate positive int value */
  if (scanf ("%u%u%u", &v, &n, &p) != 3) {
    fputs ("error: invalid unsigned integer input.\n", stderr);
    return 1;
  }
  
  /* output result */
  printf ("\nvalue of %u bits at pos %u in %u is : %u\n", 
          n, p, v, nbitsatp (v, n, p));
}

Example Use/Output

Your specific example of wanting the 3 bits beginning a position 15 of 28672:

$ ./bin/nbitsatp
enter v, n, p : 28672 3 15

value of 3 bits at pos 15 in 28672 is : 3

Or let's take the first 4 bits at position 15, 0111 (7):

$  ./bin/nbitsatp
enter v, n, p : 28672 4 15

value of 4 bits at pos 15 in 28672 is : 7

Or the first 5-bits beginning at position 15:

$ ./bin/nbitsatp
enter v, n, p : 28672 5 15

value of 5 bits at pos 15 in 28672 is : 14

Or what about the value for the 9-flags (9 bits, at position 8) which will be all zero in your example:

$ ./bin/nbitsatp
enter v, n, p : 28672 9 8

value of 9 bits at pos 8 in 28672 is : 0
  • Related