Bits Shift in C- is the i bit on? - c

I'm trying to understand the following function which decides whether a bit is on:
int isBitISet( char ch, int i )
{
char mask = 1 << i ;
return mask & ch ;
}
First, why do I get a char? for ch=abcdefgh and i=5 the function suppose to return the fifth bit from the right (?) , d. so mask=00000001<<5=00100000, and 00100000 & abcdefgh = 00c00000.
Can you please explain me how come we get char and we can do all these shifts without any casting? how come we didn't get the fifth bit and why the returned value is really the Indication whether the bit is on or not?
Edit: the 'abcdefg' are just a symbols for the bits, I didn't mean to represent a string in a char type.
I used to think of a char as 'a' and not as an actual 8 bits, so probably this is the answer to my first question.

It won't give you the fifth bit. Binary numbers start at 20, so the first bit is actually indexed with 0, not with 1. It will give return you sixth bit instead.
Examples:
ch & (1 << 0); // first bit
ch & (1 << 1); // second bit
ch & ((1 << 3) | (1 << 2)); // third and fourth bit.
Also, a char is only an interpretation of a number. On most machines it has a size of 8 bit, which you can either interpret as a unsigned value (0 to 255) or signed value (-128 to 127). So basically it's an integer with a very limited range, thus you can apply bit shifting without casting.
Also, your function will return an integer value that equals zero if and only if the given bit isn't set. Otherwise it's a non-zero value.

The function may return a char, because the input it works on is also a char only. You certainly can not pass in ch=abcdefgh, because that would be a string of 8 chars.

You can do shifts on chars, because C allows to do it. char is just an 8-bit integer type so there's no need to disallow it.
You are right about the fact, that isBitISet(abcdefgh, 5) returns 00c00000 if the letters a, b, etc. are bits in the binary representation of numbers.
The return value is not the fifth bit from the right, it is the same number as in the input, but with all the bits but the fifth bit zeroed.
You also have to remember that numbering of bits goes from zero, so the fifth bit being c is correct, just as that the zeroth bit is h.
This example uses an integer type to represent a boolean value. This is common in C code prior to C99, as C didn't have the bool type.
If you treat your return value as a boolean value, remember that everything non-zero is true, and zero is false. Hence, the output of isBitISet is true for C if bit i is set, and false otherwise.

You should know by now that in computers, everything starts with 0. That is, bit number 5 is in fact the sixth bit (not the fifth).
Your analysis is actually correct, if you give it abcdefgh and 5, you get 00c00000.
When you do the "and":
return mask & ch;
since mask has type int, ch will also automatically be cast to int (same way as many other operators). That's why you don't need explicit casting.
Finally, the result of this function is in the form 0..0z0..0. If z, the bit you are checking for is 0, this value is 0 which is false as long as an if is concerned. If it is not zero, then it is true for an if.

Do:
return 0 != (mask & ch) ;
if you want a bool (0x00000000 or 0x00000001) return. mask & ch alone will give you the bit you're asking about at correct position.
(others said more than enuff about i=5 being sixth bit)

First of all, this function does not return the i-th bit, but tells you if that bit is on or off.
The usage of char mask is implementation depend here. Simply defines an 8-bit mask since the value on which to apply this mask is a char.
Why would you need a cast when 1 is a char? i is only an value for << operator.
ch=abcdefgh makes no sense as an input. ch is char, so ch can only be one character.
The working is as follows: first you construct a mask to zero all the bits you don't need. So for example if the input is ch = 204 (ch = 11001100) and we want to know if the 6th bit is on, so i = 5. So mask = 1 << 5 = 00100000. Then this mask is applied to the value with an AND operation. This will zero everything except the bit in question: 11001100 & 00100000 = 00000000 = 0. As 0 is false in C, then 6th bit is not set. Another example on same ch input and i = 6: mask = 1 << 6 = 01000000; 11001100 & 01000000 = 01000000 = 64, which is not 0, and thus true, so 7th bit is set.

Related

what the meaning of (a&b)>>c in this systemc code? [duplicate]

This question already has answers here:
What are bitwise operators?
(9 answers)
Closed last month.
when I read SYSTEMC code,I find a function return int like this:
static inline int rp_get_busaccess_response(struct rp_pkt *pkt)
{
return (pkt->busaccess_ext_base.attributes & RP_BUS_RESP_MASK) >>
RP_BUS_RESP_SHIFT;
}
pkt->busaccess_ext_base.attributes defined as uint64_t.
RP_BUS_RESP_MASK and RP_BUS_RESP_SHIFT defined as:
enum {
RP_RESP_OK = 0x0,
RP_RESP_BUS_GENERIC_ERROR = 0x1,
RP_RESP_ADDR_ERROR = 0x2,
RP_RESP_MAX = 0xF,
};
enum {
RP_BUS_RESP_SHIFT = 8,
RP_BUS_RESP_MASK = (RP_RESP_MAX << RP_BUS_RESP_SHIFT),
};
What the meaning of this function's return?
Thanks!
a & b is a bitwise operation, this will perform a logical AND to each pair of bits, let's say you have 262 & 261 this will translate to 100000110 & 100000101 the result will be 100000100 (260), the logic behind the result is that each 1 AND 1 will result in 1 whereas 1 AND 0 and 0 AND 0 will result in 0, these are normal logical operations but are performed at bit level:
100000110
& 100000101
-----------
100000100
In (a & b) >> c, >> will shift the bits of the resulting value of a & b to the right by c positions. For example for the previous result 100000100 and having a c value of 8, all bits will shift to the right by 8, and the result is 000000001. The left most 1 bit in the original value will become the first most right whereas the third 1 bit from the right in the original value will be shifted away.
With this knowledge in mind and looking at the function, we can see that the RP_BUS_RESP_MASK constant is a mask that protects the field of bits from 9th through 12th position(from the right, i.e. the first four bits of the second byte), setting them to 1 (RP_RESP_MAX << RP_BUS_RESP_SHIFT which translates to 1111 << 8 resulting in 111100000000), this will preserve the bit values in that range. Then it sets the other bits of pkt->busaccess_ext_base.attributes to 0 when it performs the bitwise & against this mask. Finally it shifts this field to the right by RP_BUS_RESP_SHIFT(8).
It basically extracts the the first four bits in the second byte of kt->busaccess_ext_base.attributes and returns the result as an integer.
What it's for specifically? You must consult the documentation if it exists or try to understand its use in the global context, for what I can see this belongs to LibSystemCTLM-SoC (In case you didn't know)
The function extracts the first 4-Bit of the second byte of the 8-Byte (64-Bit) Attribute. This means, it extracts the following 4-Bits of the Attribute 0xFFFF FFFF FFFFF FAFF resulting in 0x0A
First it creates the mask, which is RP_BUS_RESP_MASK = 0x0F00
Next it applies the mask to the attribute pkt->busaccess_ext_base.attributes & 0x0F00 resulting in 0x0A00 from the example
Next it shifts A by 8-Bit to the right side, leading to 0x0A

What does this code does ? There are so many weird things

int n_b ( char *addr , int i ) {
char char_in_chain = addr [ i / 8 ] ;
return char_in_chain >> i%8 & 0x1;
}
Like what is that : " i%8 & Ox1" ?
Edit: Note that 0x1 is the hexadecimal notation for 1. Also note that :
0x1 = 0x01 = 0x000001 = 0x0...01
i%8 means i modulo 8, ie the rest in the Euclidean division of i by 8.
& 0x1 is a bitwise AND, it converts the number before to binary form then computes the bitwise operation. (it's already in binary but it's just so you understand)
Example : 0x1101 & 0x1001 = 0x1001
Note that any number & 0x1 is either 0 or one.
Example: 0x11111111 & 0x00000001 is 0x1 and 0x11111110 & 0x00000001 is 0x0
Essentially, it is testing the last bit on the number, which the bit determining parity.
Final edit:
I got the precedence wrong, thanks to the comments for pointing it out. Here is the real precedence.
First, we compute i%8.
The result could be 0, 1, 2, 3, 4, 5, 6, 7.
Then, we shift the char by the result, which is maximum 7. That means the i % 8 th bit is now the least significant bit.
Then, we check if the original i % 8 bit is set (equals one) or not. If it is, return 1. Else, return 0.
This function returns the value of a specific bit in a char array as the integer 0 or 1.
addr is the pointer to the first char.
i is the index to the bit. 8 bits are commonly stored in a char.
First, the char at the correct offset is fetched:
char char_in_chain = addr [ i / 8 ] ;
i / 8 divides i by 8, ignoring the remainder. For example, any value in the range from 24 to 31 gives 3 as the result.
This result is used as the index to the char in the array.
Next and finally, the bit is obtained and returned:
return char_in_chain >> i%8 & 0x1;
Let's just look at the expression char_in_chain >> i%8 & 0x1.
It is confusing, because it does not show which operation is done in what sequence. Therefore, I duplicate it with appropriate parentheses: (char_in_chain >> (i % 8)) & 0x1. The rules (operation precedence) are given by the C standard.
First, the remainder of the division of i by 8 is calculated. This is used to right-shift the obtained char_in_chain. Now the interesting bit is in the least significant bit. Finally, this bit is "masked" with the binary AND operator and the second operand 0x1. BTW, there is no need to mark this constant as hex.
Example:
The array contains the bytes 0x5A, 0x23, and 0x42. The index of the bit to retrieve is 13.
i as given as argument is 13.
i / 8 gives 13 / 8 = 1, remainder ignored.
addr[1] returns 0x23, which is stored in char_in_chain.
i % 8 gives 5 (13 / 8 = 1, remainder 5).
0x23 is binary 0b00100011, and right-shifted by 5 gives 0b00000001.
0b00000001 ANDed with 0b00000001 gives 0b00000001.
The value returned is 1.
Note: If more is not clear, feel free to comment.
What the various operators do is explained by any C book, so I won't address that here. To instead analyse the code step by step...
The function and types used:
int as return type is an indication of the programmer being inexperienced at writing hardware-related code. We should always avoid signed types for such purposes. An experienced programmer would have used an unsigned type, like for example uint8_t. (Or in this specific case maybe even bool, depending on what the data is supposed to represent.)
n_b is a rubbish name, we should obviously never give an identifier such a nondescript name. get_bit or similar would have been a better name.
char* is, again, an indication of the programmer being inexperienced. char is particularly problematic when dealing with raw data, since we can't even know if it is signed or unsigned, it depends on which compiler that is used. Had the raw data contained a value of 0x80 or larger and char was negative, we would have gotten a negative type. And then right shifting a negative value is also problematic, since that behavior too is compiler-specific.
char* is proof of the programmer lacking the fundamental knowledge of const correctness. The function does not modify this parameter so it should have been const qualified. Good code would use const uint8_t* addr.
int i is not really incorrect, the signedness doesn't really matter. But good programming practice would have used an unsigned type or even size_t.
With types unsloppified and corrected, the function might look like this:
#include <stdint.h>
uint8_t get_bit (const uint8_t* addr, size_t i ) {
uint8_t char_in_chain = addr [ i / 8 ] ;
return char_in_chain >> i%8 & 0x1;
}
This is still somewhat problematic, because the average C programmer might not remember the precedence of >> vs % vs & on top of their head. It happens to be % over >> over &, but lets write the code a bit more readable still by making precedence explicit: (char_in_chain >> (i%8)) & 0x1.
Then I would question if the local variable really adds anything to readability. Not really, we might as well write:
uint8_t get_bit (const uint8_t* addr, size_t i ) {
return ((addr[i/8]) >> (i%8)) & 0x1;
}
As for what this code actually does: this happens to be a common design pattern for how to access a specific bit in a raw bit-field.
Any bit-field in C may be accessed as an array of bytes.
Bit number n in that bit-field, will be found at byte n/8.
Inside that byte, the bit will be located at n%8.
Bit masking in C is most readably done as data & (1u << bit). Which can be obfuscated as somewhat equivalent but less readable (data >> bit) & 1u, where the masked bit ends up in the LSB.
For example lets assume we have 64 bits of raw data. Bits are always enumerated from 0 to 63 and bytes (just like any C array) from index 0. We want to access bit 33. Then 33/8 integer division = 4.
So byte[4]. Bit 33 will be found at 33%8 = 1. So we can obtain the value of bit 33 from ordinary bit masking byte[33/8] & (1u << (bit%8)). Or similarly, (byte[33/8] >> (bit%8)) & 1u
An alternative, more readable version of it all:
bool is_bit_set (const uint8_t* data, size_t bit)
{
uint8_t byte = data [bit / 8u];
size_t mask = 1u << (bit % 8u);
return (byte & mask) != 0u;
}
(Strictly speaking we could as well do return byte & mask; since a boolean type is used, but it doesn't hurt to be explicit.)

What does using bit wise AND operator on a unsigned char object after right shifting it mean?

I'm trying to understand a snippet of code which is the following:
unsigned char state = portStates[portNumber];
int bitValue = (state >> 7) & 0x1;
It's doing a bitwise AND on the least-significant bit of
state, right? If it returns true (ie, that bit is set), then the
number is odd. Otherwise, it's even. Am I correct?
Thanks
int bitValue = (state >> 7) & 0x1;
just shifts state by 7 bits. Then it removes all other bits than the first one.
So converts the 7th bit (most significant bit in most systems where unsigned char is 8 bits) of your value to 0 or 1 value. It could be written as a boolean expression (using the idiomatic double negation):
int bitValue = !!(state & 0x80);
but the shifting and masking directly gives the 0 or 1 value without converting to bool.
(state>>7) returns the value generated by shifting the unsigned char "state" by 7 bits, adding leading zeros. Performing the and operation with one now gives the value of seventh bit in state.
That is, bitValue is 1 iff the seventh bit of state (from the right) is 1, or in other words bitValue is 1 iff state >= 128.

bit comparison in loop on AVRs

I'm learning about bit logic in C on AVRs and I have a problem.
I want to compare an "i" bit (from the right) from int8_t variable and if it is 1, then do the next instruction, but it doesn't work. Here's what I write:
if (variable & (1<<i)==(1<<i)) instruction;
In example for following data:
uint8_t dot=0101;
PORTC=1;
for (int i=0; i<4; i++)
{
PORTB = fourDigit[i];
if (dot & (1<<i)==(1<<i)) PORTB--;
PORTC<<=1;
}
The dot (as it is connected to PB0) should illuminate on the first and third digit, but at present it lamps on every digit. What's the problem?
Thanks for your time.
It is done by bit masking. If you want to check whether or not an i'th bit of a is 1 you will do something like this:
if (a & (1 << i))
{
// Do something
}
This way all of the bits of a except the i'th one will be ANDed with zeros, thus getting a value of zero. The i'th bit will be ANDed with 1, thus not changing it's value. So the if condition will be true in case the bit is not zero, and false otherwise.
The comparison code you are presenting should work as well, but I suspect the dot variable is not containing the value you think it is containing. uint8_t dot=0101; makes it to be equal to 101 in octal base (due to the leading zero) or 65 in decimal. Not 101 in binary.

find ones position in 64 bit number

I'm trying to find the position of two 1's in a 64 bit number. In this case the ones are at the 0th and 63rd position. The code here returns 0 and 32, which is only half right. Why does this not work?
#include<stdio.h>
void main()
{
unsigned long long number=576460752303423489;
int i;
for (i=0; i<64; i++)
{
if ((number & (1 << i))==1)
{
printf("%d ",i);
}
}
}
There are two bugs on the line
if ((number & (1 << i))==1)
which should read
if (number & (1ull << i))
Changing 1 to 1ull means that the left shift is done on a value of type unsigned long long rather than int, and therefore the bitmask can actually reach positions 32 through 63. Removing the comparison to 1 is because the result of number & mask (where mask has only one bit set) is either mask or 0, and mask is only equal to 1 when i is 0.
However, when I make that change, the output for me is 0 59, which still isn't what you expected. The remaining problem is that 576460752303423489 (decimal) = 0800 0000 0000 0001 (hexadecimal). 0 59 is the correct output for that number. The number you wanted is 9223372036854775809 (decimal) = 8000 0000 0000 0001 (hex).
Incidentally, main is required to return int, not void, and needs an explicit return 0; as its last action (unless you are doing something more sophisticated with the return code). Yes, C99 lets you omit that. Do it anyway.
Because (1 << i) is a 32-bit int value on the platform you are compiling and running on. This then gets sign-extended to 64 bits for the & operation with the number value, resulting in bit 31 being duplicated into bits 32 through 63.
Also, you are comparing the result of the & to 1, which isn't correct. It will not be 0 if the bit is set, but it won't be 1.
Shifting a 32-bit int by 32 is undefined.
Also, your input number is incorrect. The bits set are at positions 0 and 59 (or 1 and 60 if you prefer to count starting at 1).
The fix is to use (1ull << i), or otherwise to right-shift the original value and & it with 1 (instead of left-shifting 1). And of course if you do left-shift 1 and & it with the original value, the result won't be 1 (except for bit 0), so you need to compare != 0 rather than == 1.
#include<stdio.h>
int main()
{
unsigned long long number = 576460752303423489;
int i;
for (i=0; i<64; i++)
{
if ((number & (1ULL << i))) //here
{
printf("%d ",i);
}
}
}
First is to use 1ULL to represent unsigned long long constant. Second is in the if statement, what you mean is not to compare with 1, that will only be true for the rightmost bit.
Output: 0 59
It's correct because 576460752303423489 is equal to 0x800000000000001
The problem could have been avoided in the first place by adopting the methodology of applying the >> operator to a variable, instead of a literal:
if ((variable >> other_variable) & 1)
...
I know the question has some time and multiple correct answers while my should be a comment, but is a bit too long for it. I advice you to encapsulate bit checking logic in a macro and don't use 64 number directly, but rather calculate it. Take a look here for quite comprehensive source of bit manipulation hacks.
#include<stdio.h>
#include<limits.h>
#define CHECK_BIT(var,pos) ((var) & (1ULL<<(pos)))
int main(void)
{
unsigned long long number=576460752303423489;
int pos=sizeof(unsigned long long)*CHAR_BIT-1;
while((pos--)>=0) {
if(CHECK_BIT(number,pos))
printf("%d ",pos);
}
return(0);
}
Rather than resorting to bit manipulation, one can use compiler facilities to perform bit analysis tasks in the most efficient manner (using only a single CPU instruction in many cases).
For example, gcc and clang provide those handy routines:
__builtin_popcountll() - number of bits set in the 64b value
__builtin_clzll() - number of leading zeroes in the 64b value
__builtin_ctzll() - number of trailing zeroes in the 64b value
__builtin_ffsll() - bit index of least significant set bit in the 64b value
Other compilers have similar mechanisms.

Resources