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?
- 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 least1
and at most the number of bits in theunsigned
type. - A simpler expression
((1U << N) - 1)
has undefined behavior ifN
is the number of bits in theunsigned
type. - For your example
P
is12
andN
is3
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