How do bitwise operators work in C?
bit manipulation - Bitwise Reduction Operators in C - Stack Overflow
bit manipulation - Bitwise operation |= in C - Stack Overflow
udp - C Programming - Bitwise operators and knowing when to utilize - Stack Overflow
Videos
Hey all! I got another beginner question. So, I'm learning about bitwise operators from this site. Here's what it says about the bitwise not:
Bitwise NOT is an unary operator that flips the bits of the number i.e., if the ith bit is 0, it will change it to 1 and vice versa. Bitwise NOT is nothing but simply the oneโs complement of a number. Lets take an example.
N = 5 = (101)2
~N = ~5 = ~(101)2 = (010)2 = 2
So, ~5 = 2. Now, when I try this in C:
#include <stdio.h>
int main(void) {
int c = 5;
c = ~c;
printf("%d", c);
return 0;
}
The output of the above program is -6. What am I doing wrong?
In C, assuming unsigned or twoโs complement, !~x or ~x == 0 serves as a bitwise AND; it is 1 if and only if each bit of x is 1.
!!x or x != 0 serves as a bitwise OR; it is 1 if any bit of x is 1.
The negations, not properly called NAND or NOR since they do not apply a NAND or NOR in a bitwise fashion but rather apply a NOT to the bitwise AND or OR, are simply !!~x or ~x != 0 and !x or x == 0.
There is no bitwise XOR in the operations specified by the C standard. GCC has __builtin_parity which can provide this.
The above apply to the full width of x. Narrower widths can be implemented by setting the extra bits to identity elements (1 for AND, 0 for OR and XOR).
There are no dedicated operators for this, however in most cases you can achieve the same result using bitwise operators and casting the result to a bool, which effectively is a single bit. For example:
- AND: bitwise invert, convert to bool, negate:
bool and_reduction_4_bits(int n) { return !(~n & 0b1111); // C23 adds binary literals } - OR: just convert to bool
bool or_reduction(int n) { return n; // works for any number of bits }
The tricky one is XOR reduction. This could be done if you have a way to count the number of bits set, and then just check if that number is odd. Some compilers provide a builtin popcount() function to do that. If not, you can create your own function using bit twiddling hacks.
- XOR: count bits, check if odd
bool xor_reduction(int n) { return popcount(n) & 1; }
That's not a question, that's a whole bunch. :)
- You use bitwise operators when you want to view a number as a collection of bits, rather than an integer. It's much easier to say "I want this bit-pattern shifted two bits to the left" than to create the mathematically equivalent operation. They're conceptually different; if you think of the number as bits, using a bit-operator makes more sense.
- The
& 0xffffmakes sure the value is 16 bits, by masking off all higher bits. This assumes the system'sunsigned longis at least 16 bits wide, which is a pretty safe assumption. The&(bitwiseAND) is often used for this purpose. Look at the truth table for logical conjunction and think "false is 0, true is 1" to see how this works. - The
&before the hexadecimal constant is C's bitwise AND operator, which is used to do the masking I describe above. Basically, for single-bit variablesa & b, the result is1if and only if bothaandbare 1. The operator applies this logic to each pair of bits in its input terms. - The
~operator is C's bitwise inversion, it "flips" the bits of its argument. It is commonly used to create masks.
Everything you're talking about has to do with operations on the bit level. For example "var >> num" shifts the var to the right by num (meaning it devides the var by 2^num). Also the ~var inverts the var at bit level (eg. if var = 5 in bit notation= 101 ----> ~var = 010)
Super beginner question, I apologize but I often see other people's see code and I see a lot of, 0xFE, ox00001, or >~ and I just don't understand what these are and why we need them. I google for bitwise operators and so far what I understand is that they operate on each bit of a byte and i guess & ands a 0/1, | ors >> shifts right and such. but why do we need these in actual coding environments where using these things is better than using normal variables.
also what are 0xFE called and where can I learn about them?
Remember that an XOR is the exactly same as NOT EQUALS and XNOR is exactly the same as EQUALS. So, the following will give you exactly what you want:
return !(x ^ y);
Two numbers are equal if there is no difference between them:
int equal(int x, int y){
return !(x-y);
}
Numbers can be expressed in binary like this:
3 = 000011
5 = 000101
10 = 001010
...etc. I'm going to assume you're familiar with binary.
Bitwise AND means to take two numbers, line them up on top of each other, and create a new number that has a 1 where both numbers have a 1 (everything else is 0).
For example:
3 => 00011
& 5 => 00101
------ -------
1 00001
Bitwise OR means to take two numbers, line them up on top of each other, and create a new number that has a 1 where either number has a 1 (everything else is 0).
For example:
3 => 00011
| 5 => 00101
------ -------
7 00111
Bitwise XOR (exclusive OR) means to take two numbers, line them up on top of each other, and create a new number that has a 1 where either number has a 1 AND the other number has a 0 (everything else is 0).
For example:
3 => 00011
^ 5 => 00101
------ -------
6 00110
Bitwise NOR (Not OR) means to take the Bitwise OR of two numbers, and then reverse everything (where there was a 0, there's now a 1, where there was a 1, there's now a 0).
Bitwise NAND (Not AND) means to take the Bitwise AND of two numbers, and then reverse everything (where there was a 0, there's now a 1, where there was a 1, there's now a 0).
Continuing: why does word &= 15 set all but the 4 rightmost bits to 0? You should be able to figure it out now...
n => abcdefghjikl
& 15 => 000000001111
------ --------------
? 00000000jikl
(0 AND a = 0, 0 AND b = 0, ... j AND 1 = j, i AND 1 = i, ...)
How is this useful? In many languages, we use things called "bitmasks". A bitmask is essentially a number that represents a whole bunch of smaller numbers combined together. We can combine numbers together using OR, and pull them apart using AND. For example:
int MagicMap = 1;
int MagicWand = 2;
int MagicHat = 4;
If I only have the map and the hat, I can express that as myInventoryBitmask = (MagicMap | MagicHat) and the result is my bitmask. If I don't have anything, then my bitmask is 0. If I want to see if I have my wand, then I can do:
int hasWand = (myInventoryBitmask & MagicWand);
if (hasWand > 0) {
printf("I have a wand\n");
} else {
printf("I don't have a wand\n");
}
Get it?
EDIT: more stuff
You'll also come across the "bitshift" operator: << and >>. This just means "shift everything left n bits" or "shift everything right n bits".
In other words:
1 << 3 = 0001 << 3 = 0001000 = 8
And:
8 >> 2 = 01000 >> 2 = 010 = 2
"Bit" is short for "binary digit". And yes, it's a 0 or 1. There are almost always 8 in a byte, and they're written kinda like decimal numbers are -- with the most significant digit on the left, and the least significant on the right.
In your example, w1 & 3 masks everything but the two least significant (rightmost) digits because 3, in binary, is 00000011. (2 + 1) The AND operation returns 0 if either bit being ANDed is 0, so everything but the last two bits are automatically 0.
โas concise as possibleโ is an extremely vague requirement for a quiz. Are you expected to do code golf? Does removing whitespace and parentheses make it more concise? Anyway, hereโs one solution using arithmetic on the results of comparisons:
int cmp(int x, int y) {
return (x > y) - (x < y);
}
- If
x == ythenx - y == 0. - If
x < ythenx - y < 0 - If
x > ythenx - y > 0
So we want to see if we can convert the 3 conditions described in the 3 bullet-points above into 3 single output values needed for your cmp function:
int cmp( int x, int y ) {
return -1 if x < y
return 0 if x == y
return 1 if x > y
}
This can be redefined as:
int cmp( int x, int y ) return singleValue( x - y );
int singleValue( int diff ) {
return -1 if diff < 0
return 0 if diff == 0
return 1 if diff > 0
}
Now consider (and assuming) the computer uses two's complement for 32-bit signed integers, aka int) then all negative values will have the most-significant bit (MSB, the 0th bit) set to 1.
For 32-bit integers, this means that the following expression is true for all negative numbers:
( anyNegativeNumber & 0x8000000 ) == 0x8000000
The inverse is true: all positive non-zero integers will have an MSB of 0. Finally, all zero values (int zero == 0) have all their bits set to 0.
( anyPositiveNumber & 0x8000000 ) == 0
If we look at the MSB (first-bit) in addition to checking if any other bits are 1, with the desired output from our singleValue function described above:
value | first bit | any other bits | desired output
0 | 0 | 0 | 0b ( 0)
122 | 0 | 1 | 1b ( 1)
-128 | 1 | 0 | 11111...111b (-1)
-123 | 1 | 1 | 11111...111b (-1)
We can create 0 and 1 directly from the input value by masking the bits, but -1 is a special case but we can handle that, like so:
int diff = x - y; // so only the 1st and last bits are set
If the 1st bit of the diff is set, then return -1.
If diff value is 0 then return 0
Else return 1
return ( diff & 0x80000000 == 0x80000000 ) ? 0xFFFFFFFF : ( diff != 0 );
This can be compacted:
int diff;
return ( ( ( diff = x - y ) & 0x80000000 ) == 0x80000000 ) ? 0xFFFFFFFF : ( diff != 0 );
This is still using the == and != operators though... which can be eliminated by taking advantage of the fact a single-bit (nth place) value can be shifted n-bits right to convert it to a boolean value:
( diff = x - y ) >> 31 // evaluates to 1 if x < y, 0 if x == y or x > y
The diff != 0 bit can be eliminated by taking advantage of the fact that !!a is 1 for all non-zero values and 0 for zero values:
!diff // evaluates to 1 if diff == 0, else 0
!!diff // evaluates to 0 if diff == 0, else 1
We can combine the two:
int diff;
return ( ( diff = x - y ) >> 31 ) ? -1 : !!diff;
This operation has a branch in it (?:) and a temporary variable (diff) but there is a branch-less version of the same function.
It can be seen that the three possible outputs are:
0xFFFFFFFF == 1111_1111 1111_1111 1111_1111 1111_1111 b
0x00000000 == 0000_0000 0000_0000 0000_0000 0000_0000 b
0x00000001 == 0000_0000 0000_0000 0000_0000 0000_0001 b
The >> operator has "sign extension" for signed values, which means:
1000 b >> 2 == 1110 b
0100 b >> 2 == 0001 b
So diff >> 31 will be 1111..1111 if the 0th bit is 1, otherwise is 0000..0000.
Each individual bit's value can be expressed as a function of diff:
a = ( diff >> 31 ) // due to sign-extension, `a` will only ever be either 1111..1111 or 0000..0000
b = !!diff // `b` will only ever 1 or 0
c = a | b // bitwise OR means that `1111..1111 | 0` is still `1111..1111` but `0000..0000 | 1` will be `0000..0001`.
Or just:
c = ( diff >> 31 ) | ( !!diff );
Substituting this into the expression above:
int diff = x - y;
return ( diff >> 31 ) | !!diff;
Or
int diff;
return diff = x - y, ( diff >> 31 ) | !!diff;
The comma operator must be used because C does not specify nor guarantee the evaluation order of binary operator operand expressions, but the evaluation order of the comma operator is.
As this is an inline function, and assuming we're okay with mutable arguments, then we can eliminate diff because we only use x or y once:
return x = x - y, ( x >> 31 ) | !!x;
Here's my test program and the output I get, using GCC:
#include <stdio.h>
int cmp(int x, int y) {
return x = x - y, ( x >> 31 ) | !!x;
}
int main() {
printf( "cmp( 1, 2 ) == %d\n", cmp( 1,2 ) );
printf( "cmp( 2, 2 ) == %d\n", cmp( 2,2 ) );
printf( "cmp( 2, 1 ) == %d\n", cmp( 2,1 ) );
}
Output:
cmp( 1, 2 ) == -1
cmp( 2, 2 ) == 0
cmp( 2, 1 ) == 1
Now this is not perfect because of problems of integer overflow if x and y are both large numbers and x is negative, e.g. (-4000000000) - (4000000000). Checking for this condition is possible but defeats the point of making the code as succinct as possible - you would also need to add code that handles the error condition too. In this situation, a better way would be to simply check the user-provided inputs instead of checking the function argument values.
TL;DR:
int cmp(int x, int y) {
return x = x - y, ( x >> 31 ) | !!x;
}