Why does compound bit shifting not set leading nibble to 0? [duplicate] - c

This question already has answers here:
Bit shifting a byte by more than 8 bit
(2 answers)
Closed 3 years ago.
I am trying to clear the first nibble in a 16-bit unsigned integer (set it to 0).
One of the approaches I attempted was to use left bit shifting and then right bit shifting to clear the first four bits.
Here is my program.
#include <stdio.h>
#include <stdint.h>
int main() {
uint16_t x = 0xabcd; // I want to print out "bcd"
uint16_t a = (x << 4) >> 4;
printf("After clearing first four bits: %x\n", a);
return 0;
}
I am expecting the first bit shift (x << 4) to evaluate to 0xbcd0 and then the right bit shift to push a leading 0 in front - 0x0bcd. However, the actual output is 0xabcd.
What confuses me more is if I try to use the same approach to clear the last four bits,
uint16_t a = (x >> 4) << 4;
it works fine and I get expected output: abc0.
Why, in the program above, does the right bit shifting not push a leading 0?

Happens due to integer promotion. On systems where int is larger than 16 bits, your expression is converted to
uint16_t a = (int)((int)x << 4) >> 4;
and the upper bits are not stripped therefore.

if you want to print out "bcd", maybe you can do like this:
#include <stdio.h>
#include <stdint.h>
int main() {
uint16_t x = 0xabcd; // I want to print out "bcd" // step 1
uint16_t c = x << 4 ; // step 2
uint16_t a = c >> 4; // step 3
printf("After clearing first four bits: %x\n", a);
return 0;
}
above output is :
After clearing first four bits: bcd
explanation:
when run step 1:
x is 1010101111001101 (binary) // 1010(a) 1011(b) 1100(c) 1101(d)
go to step 2:
c is 1011110011010000 (binary) // 1011(b) 1100(c) 1101(d) 0000(0)
finally go to step 3:
a is 101111001101 (binary) // 1011(b) 1100(c) 1101(d)

Related

bit programing in C [duplicate]

This question already has answers here:
How do I split up a long value (32 bits) into four char variables (8bits) using C?
(6 answers)
Closed 8 months ago.
I am new to bits programming in C and finding it difficult to understand how ipv4_to_bit_string() in below code works.
Can anyone explain that, what is happening when I pass integer 1234 to this function. Why integer is right shifted at 24,16,8 and 4 places?
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
typedef struct BIT_STRING_s {
uint8_t *buf; /* BIT STRING body */
size_t size; /* Size of the above buffer */
int bits_unused; /* Unused trailing bits in the last octet (0..7) */
} BIT_STRING_t;
BIT_STRING_t tnlAddress;
void ipv4_to_bit_string(int i, BIT_STRING_t *p)
{
do {
(p)->buf = calloc(4, sizeof(uint8_t));
(p)->buf[0] = (i) >> 24 & 0xFF;
(p)->buf[1] = (i) >> 16 & 0xFF;
(p)->buf[2] = (i) >> 8 & 0xFF;
(p)->buf[3] = (i) >> 4 & 0xFF;
(p)->size = 4;
(p)->bits_unused = 0;
} while(0);
}
int main()
{
BIT_STRING_t *p = (BIT_STRING_t*)calloc(1, sizeof(BIT_STRING_t));
ipv4_to_bit_string(1234, p);
}
An IPv4 address is four eight-bit pieces that have been put together into one 32-bit piece. To take the 32-bit piece apart into the four eight-bit pieces, you extract each eight bits separately. To extract one eight-bit piece, you shift right by 0, 8, 16, or 24 bits, according to which piece you want at the moment, and then mask with 0xFF to take only the low eight bits after the shift.
The shift by 4 instead of 0 appears to be an error.
The use of an int for the 32-bit piece appears to be an error, primarily because the high bit may be set, which indicates the int value is negative, and then the right-shift is not fully defined by the C standard; it is implementation-defined. An unsigned type should be used. Additionally, int is not necessarily 32 bits; it is preferable to use uint32_t, which is defined in the <stdint.h> header.

evaluating segments of a byte in C

I am trying to do disassembly of Intel 8080 without using disassembly tables. I read in bytes of memory and split them into sections of bits: (7, 6), (5, 4, 3), (2, 1, 0). I want to know what are the numerical values of these sections, here is an example:
given this byte:
0b00110000
bits 7 and 6 evaluate to:
0b00 -> 0
bits 5 through 3:
0b110 -> 6
bits 2 through 0:
0b000 -> 0
Now, I am very inexperienced with C and I'm having a hard time coming up with an elegant and simple solution to this problem. So far my idea was the following:
Create 3 copies of the byte (1 per section)
Clear all bits apart from the ones I'm interested in (bitwise AND mask)
Shift the byte an appropriate number of bits
Read the value
would this do the job or is there a better way?
If you think about what needs to be done, you only need be concerned about unary >> shift operator and the & operator. It also helps to come up with a bit mask to isolate only those wanted bits out of whatever intermediate calculation as may be required. (a bit mask is simply a variable holding a number whose 1 bits and 0 bits can by used in a bitwise operation to give you your desired result).
Here, in all your separating of bits, you will only be concerned with the 2 or 3 lower bits after you shift to get your final result. In the case you are looking at (7,6), there are no further bits to mask leaving only the case where you are looking at the lower 3 bits that will require a mask.
From a bit-mask (or what's the magic number) standpoint, you want a mask that will preserve the last 3-bits and discard all remaining higher bits. So for an 8-bit value you want 00000111, or simply the number 7.
To begin, if you want to examine the highest 2 bits in an 8-bit number, then you simply need to shift your number by 6 to the right, e.g. given a byte b holding the total value 0x00110000 in your case, you need.
b >> 6;
There is no need to mask anything here since no higher bits remain.
For bits (5,4,3) in your example, you need to shift to the right by 3, then you will need to & the intermediate result with your mask (7 or b00000111) to get rid of the two bits that remain (6,7), e.g.
uint8_t mask = 7;
...
(b >> 3) & mask;
In the last part, your (2,1,0) bits, no shifting is required, you just need to wipe out all bits over bit 2, e.g. get rid of (7,6,5,4,3) using your mask,
b & mask
Putting that altogether, using exact width types, you can do something similar to the following. The program takes your byte value as its first argument (using 48, e.g. 0x0011000 by default if no argument is given) and outputs the results of the shifts and masks:
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
int main (int argc, char *argv[]) {
uint64_t tmp = argc > 1 ? strtoul (argv[1], NULL, 0) : 48;
uint8_t b = 0,
mask = 7;
if (tmp > UINT8_MAX) {
fprintf (stderr, "input exceeds UINT8_MAX.\n");
return 1;
}
b = (uint8_t)tmp;
printf ("(7,6) 0x%02" PRIx8 "\n", b >> 6);
printf ("(5,4,3) 0x%02" PRIx8 "\n", (b >> 3) & mask);
printf ("(2,1,0) 0x%02" PRIx8 "\n", b & mask);
return 0;
}
Example Use/Output
$ /bin/bytes_233
(7,6) 0x00
(5,4,3) 0x06
(2,1,0) 0x00
Look things over and let me know if you have further questions.
To parse out specific bits of a binary value, we use bit shifts and bit masks. Any segment of bits can be obtained in this manner, using the concept of:
(data >> n) & mask
Where data is the raw data, n is the bit position where this data starts and mask is a bit mask of "all ones", corresponding to the length of the segment.
The mask of "all ones" can be obtained from knowing the segment size: (1u << size) - 1. If a segment's size is for example 3 bits, then 1<<3 gives 1000b. 1000b - 1 = 111b, which is a "all ones" mask of 3 bits.
So if we know the size in bits and the bit position (offset), we can get the data. Example:
#include <stdio.h>
#include <inttypes.h>
#define SEG1_BITS 2
#define SEG1_OFFSET 6
#define SEG2_BITS 3
#define SEG2_OFFSET 3
#define SEG3_BITS 2
#define SEG3_OFFSET 0
#define SEG1(d) ( ((uint32_t)d >> SEG1_OFFSET) & ((1u<<SEG1_BITS)-1) )
#define SEG2(d) ( ((uint32_t)d >> SEG2_OFFSET) & ((1u<<SEG2_BITS)-1) )
#define SEG3(d) ( ((uint32_t)d >> SEG3_OFFSET) & ((1u<<SEG3_BITS)-1) )
int main (void)
{
uint8_t data = 0x30;
printf("%"PRIu32"\n", SEG1(data));
printf("%"PRIu32"\n", SEG2(data));
printf("%"PRIu32"\n", SEG3(data));
return 0;
}
Advanced version with "X macro" to avoid code repetition:
#include <stdio.h>
#include <inttypes.h>
#define SEG_LIST \
/*bits, offset */ \
X(2, 6) \
X(3, 3) \
X(2, 0)
#define SEG(data, bits, n) ( ((uint32_t)data >> n) & ((1u<<bits)-1) )
int main (void)
{
uint8_t data = 0x30;
#define X(bits, n) printf("%"PRIu32"\n", SEG(data, bits, n));
SEG_LIST
#undef X
return 0;
}
Since the problem turned out to be of expansive nature, I had to generalise it and wrote this method:
uint8_t bitsAsValue(uint8_t* byte, int start, int end) {
uint8_t mask = 0b00000000;
uint8_t mask_setter = 0b00000001;
for (int i = start; i <= end; i++) {
mask |= (mask_setter << i);
}
uint8_t value = *byte & mask;
value = value >> start;
return value;
}
It will extract the value from a continuous segment of a byte.

Iterate through bits in C

I have a big char *str where the first 8 chars (which equals 64 bits if I'm not wrong), represents a bitmap. Is there any way to iterate through these 8 chars and see which bits are 0? I'm having alot of trouble understanding the concept of bits, as you can't "see" them in the code, so I can't think of any way to do this.
Imagine you have only one byte, a single char my_char. You can test for individual bits using bitwise operators and bit shifts.
unsigned char my_char = 0xAA;
int what_bit_i_am_testing = 0;
while (what_bit_i_am_testing < 8) {
if (my_char & 0x01) {
printf("bit %d is 1\n", what_bit_i_am_testing);
}
else {
printf("bit %d is 0\n", what_bit_i_am_testing);
}
what_bit_i_am_testing++;
my_char = my_char >> 1;
}
The part that must be new to you, is the >> operator. This operator will "insert a zero on the left and push every bit to the right, and the rightmost will be thrown away".
That was not a very technical description for a right bit shift of 1.
Here is a way to iterate over each of the set bits of an unsigned integer (use unsigned rather than signed integers for well-defined behaviour; unsigned of any width should be fine), one bit at a time.
Define the following macros:
#define LSBIT(X) ((X) & (-(X)))
#define CLEARLSBIT(X) ((X) & ((X) - 1))
Then you can use the following idiom to iterate over the set bits, LSbit first:
unsigned temp_bits;
unsigned one_bit;
temp_bits = some_value;
for ( ; temp_bits; temp_bits = CLEARLSBIT(temp_bits) ) {
one_bit = LSBIT(temp_bits);
/* Do something with one_bit */
}
I'm not sure whether this suits your needs. You said you want to check for 0 bits, rather than 1 bits — maybe you could bitwise-invert the initial value. Also for multi-byte values, you could put it in another for loop to process one byte/word at a time.
It's true for little-endian memory architecture:
const int cBitmapSize = 8;
const int cBitsCount = cBitmapSize * 8;
const unsigned char cBitmap[cBitmapSize] = /* some data */;
for(int n = 0; n < cBitsCount; n++)
{
unsigned char Mask = 1 << (n % 8);
if(cBitmap[n / 8] & Mask)
{
// if n'th bit is 1...
}
}
In the C language, chars are 8-bit wide bytes, and in general in computer science, data is organized around bytes as the fundamental unit.
In some cases, such as your problem, data is stored as boolean values in individual bits, so we need a way to determine whether a particular bit in a particular byte is on or off. There is already an SO solution for this explaining how to do bit manipulations in C.
To check a bit, the usual method is to AND it with the bit you want to check:
int isBitSet = bitmap & (1 << bit_position);
If the variable isBitSet is 0 after this operation, then the bit is not set. Any other value indicates that the bit is on.
For one char b you can simply iterate like this :
for (int i=0; i<8; i++) {
printf("This is the %d-th bit : %d\n",i,(b>>i)&1);
}
You can then iterate through the chars as needed.
What you should understand is that you cannot manipulate directly the bits, you can just use some arithmetic properties of number in base 2 to compute numbers that in some way represents some bits you want to know.
How does it work for example ? In a char there is 8 bits. A char can be see as a number written with 8 bits in base 2. If the number in b is b7b6b5b4b3b2b1b0 (each being a digit) then b>>i is b shifted to the right by i positions (in the left 0's are pushed). So, 10110111 >> 2 is 00101101, then the operation &1 isolate the last bit (bitwise and operator).
If you want to iterate through all char.
char *str = "MNO"; // M=01001101, N=01001110, O=01001111
int bit = 0;
for (int x = strlen(str)-1; x > -1; x--){ // Start from O, N, M
printf("Char %c \n", str[x]);
for(int y=0; y<8; y++){ // Iterate though every bit
// Shift bit the the right with y step and mask last position
if( str[x]>>y & 0b00000001 ){
printf("bit %d = 1\n", bit);
}else{
printf("bit %d = 0\n", bit);
}
bit++;
}
}
output
Char O
bit 0 = 1
bit 1 = 1
bit 2 = 1
bit 3 = 1
bit 4 = 0
bit 5 = 0
bit 6 = 1
bit 7 = 0
Char N
bit 8 = 0
bit 9 = 1
bit 10 = 1
...

Bit masking and separation in c

I am new to c programming and i need help in bit manipulation.
I would like to separate the number from a register which have encoded numbers in BCD.
for example;
the register got '29' as value two bits will denote 2 ='10' and four bits will denote 9='1001'.
It is an 8 bit register and rest bits are zero.
So shifting out the 4 bits will give me 2 at disposal.But what about getting the unit digit?
I need some help regarding that
I'm posting the code here:
#include<stdio.h>
main()
{
int x,y;
y=0x29;
x=y;
x=x>>4;
x=x*10;
printf("%d",x);
return(0);
}
You need to mask it out with binary 00001111, which is decimal 15 or hexadecimal 0x0f.
uint8_t reg = 41; // binary 00101001
uint8_t lo_nibble = (reg >> 0) & 0x0f;
uint8_t hi_nibble = (reg >> 4) & 0x0f;
To form a mask to capture the bottom n bits of a number, you can perform these steps (pen and paper at first, eventually in your head):
start with the value 1.
(1) // == 1 or 00000001
shift the value 1 up by n bits.
(1<<4) // == 16 or 00010000
subtract 1.
(1<<4)-1 // == 15 or 00001111
ANDing this mask with another value or variable will yield the bottom n bits of the number.
int in, hi, lo;
lo = in & ((1<<4)-1);
hi = (in>>4) & ((1<<4)-1);

Left Bit Shift In C without extension

I was wondering how to get C to not extend my binary number when I bitshift to the left
int main ()
{
unsigned int binary_temp = 0b0100;
binary_temp = binary_temp << 2;
printf("%d", binary_temp);
return 0;
}
When I run that I want a return value of 0 since it has extended past the 4 digits I have, but right now it returns 16 (10000). How would I get C not to extend my number?
Edit: I would like to be able to work with the number in binary form so I need to have only 4 digits, and not just outputting the right number.
It does not extend your number but saves it as unsigned int type which is 4 bytes (32 bits) in size. You only fill the last 4 bits. To treat it as only 4 bits, use Bitwise AND with a Mask value. Here's example code:
int main()
{
unsigned int binary_temp = 0b0100;
binary_temp = (binary_temp << 2) & 0b1111;
printf("%u", binary_temp);
return 0;
}
You can bitwise AND the result with a 4 bit mask value:
binary_temp = (binary_temp << 2) & 0xF;
There is no 0b in standard C. You could use 4.
unsigned int /* prepare for wtf identifier: */
binary_temp = 4;
Left shifting by 2 is multiplying by 4. Why not?
binary_temp *= 4;
... and then reduce modulo 16?
binary_temp %= 16;
What sense is there to using binary operators, in this case? I see none.
The %d directive corresponds to an int argument, but the argument you're giving printf is an unsigned int. That's undefined behaviour.
printf("%u", binary_temp);
I'm sure whichever book you're reading will tell you about the %u directive.

Resources