How to work with individual bits? [duplicate] - c

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Explanation of an algorithm to set, clear and test a single bit
I have an unsigned char. I would like to have bits 2 through 4 (counting from the least significant bit as 0) copied to another unsigned char as the first three bits. For example, in
abcdefgh // a,b,c,d,e,f,g,h are 0 or 1
becomes
00000def
I have tried
unsigned char input, output;
output = (input << 3) >> 5;
which does not work, but
output = (input << 3)
output >>= 5;
does work.
Is there a way in C to accomplish this in one line?

shift it, then mask the rest off:
output = ( input >> 2 ) & 0x07;

This gets only the bits you want then shifts them to the right. It's the opposite approach of #rsaxvc.
output = (input & 28) >> 2;

Try this:
unsigned char input, output;
input = 0x12abcdef;
output = ((input & 0x00fff000) >> 3) & 0x00000fff;
I don't think you can just shift back and forth on the same line and assume every time you shift the space is filled by zeroes, but this may be compiler dependent, if you do this you'll get the right thing guaranteed.
I'm assuming by "first three bits" you mean the 3 least significant bits, which is the leftmost or first 3 bits on little-endian systems.

Related

Swapping bits in an integer in C, can you explain this function to me?

I want to write a function that receives an unsigned char and swaps between bit 2 and bit 4 and returns the new number.
I am not allowed to use if statement.
So I found this function, among other functions, but this was the most simple one to understand (or try to understand).
All other functions involve XOR which I don't really understand to be honest.
unsigned char SwapBits(unsigned char num)
{
unsigned char mask2 = ( num & 0x04 ) << 2;
unsigned char mask4 = ( num & 0x10 ) >> 2;
unsigned char mask = mask3 | mask5 ;
return ( num & 0xeb ) | mask;
}
Can someone explain me what happens here and most important, why?
Why AND is required here and why with hex address?
Why should I AND with 0xeb (255)? I know that's the range of char but why should I do that.
In short,
I know how to read codes. I understand this code, but I don't understand the purpose of each line.
Thanks.
First, the usual convention is that bits are numbered starting from 0 for the least significant bit and counting up. In this case, you have an 8-bit value, so the bits go from 0 on the right up to 7 on the left.
The function you posted still isn't quite right, but I think I see where you (it) was going with it. Here are the steps it's doing:
Pull out bit 2 (which is 3rd from the right) using a mask
Pull out bit 4 (which is 5th from the right) using a mask
Shift bit 2 left 2 positions so it's now in bit 4's original position
Shift bit 4 right 2 positions so it's now in bit 2's original position
Join these two bits together into one value that is now bits 2 and 4 swapped
Mask out (erase using &) only bits 2 and 4 from the original value
Join in (insert using |) the new swapped bits 2 and 4 to complete the transformation
I have rewritten the function to show each step one at a time to help make it clearer. In the original function or other examples you find, you'll see many of these steps all happen together in the same statement.
unsigned char SwapBits(unsigned char num)
{
// preserve only bit 2
unsigned char bit2 = num & 0x04;
// preserve only bit 4
unsigned char bit4 = num & 0x10;
// move bit 2 left to bit 4 position
unsigned char bit2_moved = bit2 << 2;
// move bit 4 right to bit 2 position
unsigned char bit4_moved = bit4 >> 2;
// put the two moved bits together into one swapped value
unsigned char swapped_bits = bit2_moved | bit4_moved;
// clear bits 2 and 4 from the original value
unsigned char num_with_swapped_bits_cleared = num & ~0x14;
// put swapped bits back into the original value to complete the swap
return num_with_swapped_bits_cleared | swapped_bits;
}
The second to last step num & ~0x14 probably needs some explanation. Since we want to save all the original bits except for bits 2 and 4, we mask out (erase) only the bits we're changing and leave all the others alone. The bits we want to erase are in positions 2 and 4, which are the 1s in the mask 0x14. So we do a complement (~) on 0x14 to turn it into all 1s everywhere except for 0s in bits 2 and 4. Then we AND this value with the original number, which has the effect of changing bits 2 and 4 to 0 while leaving all the others alone. This allows us to OR in the new swapped bits as the final step to complete the process.
You have to read about binary representation of number
unsigned char SwapBits(unsigned char num)
{
// let say that [num] = 46, it means that is is represented 0b00101110
unsigned char mask2 = ( num & 0x04 ) << 2;
// now, another byte named mask2 will be equal to:
// 0b00101110 num
// 0b00000100 0x04
// . .1. mask2 = 4. Here the & failed with . as BOTH ([and]) bits need to be set. Basically it keeps only numbers that have the 3rd bit set
unsigned char mask4 = ( num & 0x10 ) >> 2;
// 0b00101110 num
// 0b00010000 0x10 -> means 16 in decimal or 0b10000 in binary or 2^4 (the power is also the number of trailing 0 after the bit set)
// 0b00.....0 mask4 = 0, all bits failed to be both set
unsigned char mask = mask3 | mask5 ;
// mask will take bits at each position if either set by mask3 [or] mask5 so:
// 0b1001 mask3
// 0boo11 mask4
// 0b1011 mask
return ( num & 0xeb ) | mask; // you now know how it works ;) solve this one. PS: operation between Brackets have priority
}
If you are interested to learn the basics of bitwise operators you can take a look at this introduction.
After you build confidence you can try solving algorithms using only bitwise operators, where you will explore even deeper bitwise operations and see its impact on the runtime ;)
I also recommend reading Bit Twiddling Hacks, Oldies but Goodies!
b = ((b * 0x80200802ULL) & 0x0884422110ULL) * 0x0101010101ULL >> 32; // reverse your byte!
Simple function to understand swap of bit 3 and 5:
if you want to swap bit index 3 and bit index 5, then you have to do the following:
int n = 0b100010
int mask = 0b100000 // keep bit index 5 (starting from index 0)
int mask2 = 0b1000 // keep bit index 3
n = (n & mask) >> 2 | (n & mask2) << 2 | (n & 0b010111);
// (n & mask) >> 2
// the mask index 5 is decrease by 2 position (>>2) and brings along with it the bit located at index 5 that it had captured in n thanks to the AND operand.
// | (n & mask2) << 2
// mask2 is increased by 2 index and set it to 0 since n didn't have a bit set at index 3 originally.
// | (n & 0b010111); // bits 0 1 2 and 4 are preserved
// since we assign the value to n all other bits would have been wiped out if we hadn't kept their original value thanks to the mask on which we do not perform any shift operations.

Bitwise masking

Assuming an environment where long int is a 64-bit type, suppose I have an long int = 0x0123456789ABCDEF and I want to get the byte that represents 89. Would this line work?
n = (n >> (b << 3)) & 0xFF;
where n is the long int and b is the byte I want. So b would be 3 and shifting it left 3 would multiply it by 8 changing it into a byte so shifting should look like this 0x0123456789. Is using & 0xFF the right way to mask to get the last byte?
Yes, this is the correct approach. This online example on ideone.com prints 89 as expected.

Read a single bit from a buffer of char

I would to implement a function like this:
int read_single_bit(unsigned char* buffer, unsigned int index)
where index is the offset of the bit that I would want to read.
How do I use bit shifting or masking to achieve this?
You might want to split this into three separate tasks:
Determining which char contains the bit that you're looking for.
Determining the bit offset into that char that you need to read.
Actually selecting that bit out of that char.
I'll leave parts (1) and (2) as exercises, since they're not too bad. For part (3), one trick you might find useful would be to do a bitwise AND between the byte in question and a byte with a single 1 bit at the index that you want. For example, suppose you want to get the fourth bit out of a byte. You could then do something like this:
Byte: 11011100
Mask: 00001000
----------------
AND: 00001000
So think about the following: how would you generate the mask that you need given that you know the bit index? And how would you convert the AND result back to a single bit?
Good luck!
buffer[index/8] & (1u<<(index%8))
should do it (that is, view buffer as a bit array and test the bit at index).
Similarly:
buffer[index/8] |= (1u<<(index%8))
should set the index-th bit.
Or you could store a table of the eight shift states of 1 and & against that
unsigned char bits[] = { 1u<<0, 1u<<1, 1u<<2, 1u<<3, 1u<<4, 1u<<5, 1u<<6, 1u<<7 };
If your compiler doesn't optimize those / and % to bit ops (more efficient), then:
unsigned_int / 8 == unsigned_int >> 3
unsigned_int % 8 == unsigned_int & 0x07 //0x07 == 0000 0111
so
buffer[index>>3] & (1u<<(index&0x07u)) //test
buffer[index>>3] |= (1u<<(index&0x07u)) //set
One possible implementation of your function might look like this:
int read_single_bit(unsigned char* buffer, unsigned int index)
{
unsigned char c = buffer[index / 8]; //getting the byte which contains the bit
unsigned int bit_position = index % 8; //getting the position of that bit within the byte
return ((c >> (7 - bit_position)) & 1);
//shifting that byte to the right with (7 - bit_position) will move the bit whose value you want to know at "the end" of the byte.
//then, by doing bitwise AND with the new byte and 1 (whose binary representation is 00000001) will yield 1 or 0, depending on the value of the bit you need.
}

Function that reset the 8th bit of the string?

I am trying make a code that resets the 8th bit of the string. I have made it work, but I believe it is not still correct. Here is the code:
#include <stdio.h>
#include <stdlib.h>
void make7bit(unsigned char *s, unsigned int n)
{
int i = 0;
int x =0;
while(x <n)
{
if(*s |= (1 << 7)) //it still works, whatever I have 1 << 7 or 1 << 3
*s = '0';
i++;
x++;
}
printf("%s", s);
return NULL;
}
int main()
{
char A[] ={"11111111"};
int n = 8;
make7bit(A, n);
return 0;
}
I dont understand the line if(*s |= (1 << 7)), because whatever it is 1 << 7 or something else (for example 1 << 3) it still works, or at least it reset the last bit of the string. I am quite sure I am doing something wrong here, but what? I think the code is now resetting the last bit of the string and not the 8th one as I would like...
Could someone help me with this one?
1 << 3 is 00001000, 1 << 7 is 10000000.. You're not clearing the 8th bit in any case.
If you want to clear a bit (not setting it), you should:
*s &= ~(1 << 7);
Your question is unclear. What does it means '8th bit of the string'? You should reset 8th bit of every byte? Or something else? Why do you set *s to '0'? Should results for "11111111" and "12345678" be the same? Do you assume usual string, or maybe every char represents one bit?
If you wish to reset 8th bit of every byte, you should use
*s &= 0x7F;
But generally your source contains no any line which corresponts to task described.
Btw, your loop is senseless. You described two loop variables, but never use it; you just patches one byte 8 times in a row.
Your are done the left shift with the value one.
1 << 7
Now the bit is 10000000.
So you are doing the or operation with this value. Here *s value is,
*s=1. Bit position of one is. 00110001.
Because ascii value of 1 is 49.Here you are using the character so the value is taken in ascii. And bit representation for one byte.Now or operation.
00110001
10000000
---------
10110001
So the value is non zero so the if condition works and the position is changed into 0.

Unexepected behavior from multiple bitwise shifts on the same line [duplicate]

This question already has answers here:
Why does combining two shifts of a uint8_t produce a different result?
(2 answers)
Closed 8 years ago.
I get a different result depending on if I combine multiple bitwise shifts on one line or put them on separate lines.
unsigned char a = 73;
a = (a << 6) >> 2;
printf("%d\n", a);
prints 144 when I expect 16
unsigned char a = 73;
a = a << 6;
a = a >> 2;
printf("%d\n", a);
prints the expected result of 16
when I shift left 6, then right 1 on one line, it prints the expected result of 32, so it
looks like the 2nd shift right is shifting in a 1 instead of a 0, but why?
Also
a = (unsigned char) (a << 6 ) >> 2;
produces the expected result (16).
Is the first left shift returning a signed char instead of an unsigned char, and if so why?
Yes, the result of the first shift is signed. signed int specifically. Check out the rules for the "integer promotions" in the C spec:
If an int can represent all values of the original type ... the value is converted to an int...
So, since your int - usually a range of [-231, 231) - can represent all the values of unsigned char - usually [0, 255] - it's converted to int, and the << and >> take place on the resulting values.

Resources