I am learning about masking techniques in C.
Here is a practice problem I am working on:
Need to find the complement of 0x87654321 while leaving the least significant byte intact which should look like this 0x789ABC21
The only mask I'm familiar with right now is using x & 0xFF to strip all but the last byte. I don't know which bitwise operator to use to get the complement of a hex number. How do I approach that?
My book doesn't explain what a one complement of a hex number is but I googled that and found out the shortcut method to determine a one complement is to take 15 - hexDigit = complement Please correct me if I'm wrong.
The bitwise complement operator in C is the tilde ~. This flips every bit in a bit pattern.
The bitwise XOR operator (^) can also be used to do a bitwise complement. The bitwise XOR truth table is below:
^| 0 1
------
0| 0 1
1| 1 0
Notice in particular that 1^0 = 1 and that 1^1 = 0. Thus, bitwise XOR with a one will also have the effect of flipping bits.
Thus, bitwise XOR with 0xFFFFFF00 will flip all but the last eight bits of a number.
Related
Assignment operators are not something I expected to struggle with. Everything in this section so far is familiar, but the way they explain it makes it seem foreign. I think it's the bitwise operators I'm confused about.
Anyway here is the part I don't get.
The function bitcount counts the number of 1-bits in its integer argument.
/*bitcount: count 1 bits in x */
int bitcount (unsigned x)
{
int b;
for(b=0; x != 0; x >>= 1) {
if(x & 01)
b++;
return b;
}
Declaring the argument x to be unsigned ensures that when it is right-shifted, vacated bits will be filled with zeros, not sign bits, regardless of the machine the program is run on.
Not that I really understand the code, but this last sentence is confusing me the most. What does this mean? Does it mean "ones" by "sign bits" and does this have to do with twos complement?
I really had trouble getting through the bitwise operations. Can anyone recommend some comprehensive material to supplement the bitwise stuff in this book?
Suppose x is two’s complement. For illustration, let‘s use an eight-bit width. (C always shifts in a wider width, at least that of int.)
If x is 64 (010000002) and we shift it right one bit, we get 32 (001000002). When we repeat that, we get 16 (000100002), 8 (000010002), 4 (000001002), 2 (000000102) , and 1 (000000012).
When x is −64, two’s complement represents it with 110000002. If we shift that right and bring in a 0 bit, the bits are 011000002, which represents 64+32 = 96. So −64 becomes 96. Now, that might be fine if one were just working with bits. But, if we want to use bit-shifting to divide numbers, we want −32, not 96. The bits for −32 are 111000002. So we can get that by bring in a 1 bit instead of a 0 bit. And the bits for −16 are 111100002. Then −8, −4, −2, and −1 are 111110002, 111111002, 111111102, 111111112. In each case, we bring in a 1 bit when shifting.
So, if we want to use bit-shifting for division, there is a simple rule for a one-bit shift: Shift all bits right one spot and leave the sign bit as is (0 or 1). If we are shifting more than one bit, keep copying the sign bit.
That is called an arithmetic right shift. So, we have two kinds of right shift: An arithmetic right shift that copies the sign bit, and a logical right shift that brings in 0 bits.
For unsigned types, the C standard says a right shift is logical.
For signed types, the C standard does not say whether it is arithmetic or logical. It leaves it to the implementation to define which that implementation uses (or possibly to define something else). That might be due to the history; early machines might not have provided arithmetic right-shift instructions (and may not even have used two’s complement), although it seems hard to imagine these days.
So, when you are writing code that shifts right and you want to be sure of the result you will get, you can use an unsigned type to be sure to get a logical shift.
In twos complement representation the highest order bit is reserved for the sign. The highest order bit is 0 for positive numbers and 1 for negative numbers.
If you right shift the bits of a negative number the 1 originally in the highest order bit will be shifted to the next lower order bit, eventually ending up in the lowest order bit if you keep shifting the bits.
In the code the for loop shifts the bits of x by one bit position and assigns the shifted value to x.
for (b = 0; x != 0; x >>=1 )
First b, which is used to count the number of 1 bits in the number is set to 0.
The condition to continue the loop is x != 0. When all the 1 bits are shifted out of x the only thing left will be 0 bits. x will then equal 0.
The operation performed after each iteration is to right-shift the value in x by 1.
The if condition in the body of the loop performs bit-wise AND operation on x. The bit mask has a value of 1, which is an instance of the int value with all bits 0 except the lowest order bit. That AND operation will evaluate to 1 (or true in C) if the lowest order bit is 1, and to 0 (or false in C) if the lowest order bit is 0. The count of one bits is incremented if the if condition is true.
This question already has answers here:
What does ~0 do?
(4 answers)
Closed 7 years ago.
Why does printf("%d", ~0); yield a value of -1? Shouldn't it be 1 since the ~ operator converts each 1-bit into a 0-bit and vice versa?
From what I understand is 0000 will be negated to 1111.
~ is a bitwise complement operator . 00000000 is flipped to 11111111.
If you take 2'scomplement of 1(00000001) what you get is 11111111 which is to represent -1 in binary.
Therefore the output is -1.
Try to see the hex part of it.
printf("%x", ~0);
It will print ffff which means it negates every bit so 0000000000000000 is converted to 1111111111111111.
As per logic, if first bit is 1 then it is treated as negative number.
hence -1.
In 32-bit machine 0 represent as
00000000000000000000000000000000
As when you apply biwise NOT(~) then it flip all bit then bit representation like be
11111111111111111111111111111111
which is -1 representation of 2s complement.
In C/C++, ~ is the bitwise complement operator. For any given bitwise-complementable object x, it'll flip all binary digits found in the raw representation of x. Thus, if an integer x is represent in binary as 0b00000000, it'll become 0x11111111.
BUT!!!!!
The answer is not always -1. What happens is that there are two ways to represent negative numbers in existence, namely one's complement, and two's complement.
One's complement
For any number x, -x is represented as the bitwise complement of x.
Two's complement
For any number x, -x is represented as one plus the bitwise complement of x.
The real world
Find me a (modern) system using one's complement and I give you a free cookie! The fact is that one's complement allows for such nonsenses as -0, and in fact, your code would render that on a one's complement machine.
BTW, as other answers have already posted, the actual printing (not internal representation) of a number may vary if it's casted (unsigneds just ignore the extra top bit and thus allow for twice range before overflowing).
%d takes signed integer
different variations of same input
Signed Value ~0 -1
UnSigned Value ~0 4294967295
Hex Value ~0 ffffffff
Hex Value ~0 FFFFFFFF
as you can see the signed bit is set and its nothing but 2's compliment of 1
as a rule
-ve of n = (~n) + 1;
complement of 5 is -6
and complement(5)+1 is -5
In programming languages operators like & and | are called bit wise operators. My question is even addition(+) and subtraction(-) or to that matter any mathematical expressions are bit wise operations. I mean the calculation happens on binary data as machine cannot understand decimals. I think for addition also there will be an add gate so why only operators like & and |(or) are called bit wise operators.
Because the bitwise operators only operate on the bits, they do nothing "more" and there's no question of the underlying format.
Addition treats a bunch of bits as a number, which might be signed (or even floating point); this means it must interpret the bits in a particular way (e.g. two's complement, signed magnitude, floating point, and so on), while the bitwise operators treat the bits as just "raw" bits, with no interpretation and no dependencies between bits as there might be in the higher-level numerical formats.
Also, you forgot some: there's also the ^ bitwise XOR operator, ~ which is bitwise not, and of course the shifting operators << and >>.
In the C language, there are a lot of operators called bitwise: & | ^ << >> ~ &= |= ^= <<= >>= ~=. They have in common that they are only used for bit manipulation on the "raw binary level", regardless of what kind of data the variable contains.
But of course, all operators have the purpose of altering bits. Bitwise is just a naming convention by the C language. Strictly speaking, C groups operators together in different groups with related operators, like this (C11 6.5):
Additive operators + -
Bitwise shift operators >> <<
Bitwise AND operator &
Bitwise exclusive OR operator ^
Bitwise inclusive OR operator |
And so on.
^ (XOR) and the shift operators are also bitwise operators. The difference between these and other operators is mainly that bitwise operators do not assume a particular encoding of a value, as is the case with the two's complement representation of integers. A small exception to this rule is that >> makes no sense unless the leftmost bit is interpreted as a sign bit.
In bitwise operations, the value of the bit at some particular position in the result may depend from the value of the bit in the same position in operands but does not depend on bit values in any other positions.
With one operand, there are 2 possible inputs (false, true) so 4 bitwise operations are possible (x, not x, 0 and 1). With two operands, there are 4 possible input combinations so in total 16 such operations are possible (and, or, xor, not x, not y, x, y, 0, 1, etc).
This question already has answers here:
Arithmetic bit-shift on a signed integer
(6 answers)
Closed 9 years ago.
so, lets say I have a signed integer (couple of examples):
-1101363339 = 10111110 01011010 10000111 01110101 in binary.
-2147463094 = 10000000 00000000 01010000 01001010 in binary.
-20552 = 11111111 11111111 10101111 10111000 in binary.
now: -1101363339 >> 31 for example, should equal 1 right? but on my computer, I am getting -1. Regardless of what negative integer I pick if x = negative number, x >> 31 = -1. why? clearly in binary it should be 1.
Per C99 6.5.7 Bitwise shift operators:
If E1 has a signed type and a negative value, the resulting value is implementation-defined.
where E1 is the left-hand side of the shift expression. So it depends on your compiler what you'll get.
In most languages when you shift to the right it does an arithmetic shift, meaning it preserves the most significant bit. Therefore in your case you have all 1's in binary, which is -1 in decimal. If you use an unsigned int you will get the result you are looking for.
Per C 2011 6.5.7 Bitwise shift operators:
The result of E1 >> E2 is E1 right-shifted E2 bit positions. If E1 has an unsigned type
or if E1 has a signed type and a nonnegative value, the value of the result is the integral
part of the quotient of E1/ 2E2. If E1 has a signed type and a negative value, the
resulting value is implementation-defined.
Basically, the right-shift of a negative signed integer is implementation defined but most implementations choose to do it as an arithmetic shift.
The behavior you are seeing is called an arithmetic shift which is when right shifting extends the sign bit. This means that the MSBs will carry the same value as the original sign bit. In other words, a negative number will always be negative after a left shift operation.
Note that this behavior is implementation defined and cannot be guaranteed with a different compiler.
What you are seeing is an arithmetic shift, in contrast to the bitwise shift you were expecting; i.e., the compiler, instead of "brutally" shifting the bits, is propagating the sign bit, thus dividing by 2N.
When talking about unsigned ints and positive ints, a right shift is a very simple operation - the bits are shifted to the right by one place (inserting 0 on the left), regardless of their meaning. In such cases, the operation is equivalent to dividing by 2N (and actually the C standard defines it like that).
The distinction comes up when talking about negative numbers. Several negative numbers representation exist, although currently for integers most commonly 2's complement representation is used.
The problem of a "brutal" bitwise shift here is, for starters, that one of the bits is used in some way to express the sign; thus, shifting the binary digits regardless of the negative integers representation can give unexpected results.
For example, commonly in 2's representation the most significant bit is 1 for negative numbers, 0 for positive numbers; applying a bitwise shift (with zeroes inserted to the left) to a negative number would (between other things) make it positive, not resulting in the (usually expected) division by 2N
So, arithmetic shift is introduced; negative numbers represented in 2's complement have an interesting property: the division by 2N behavior of the shift is preserved if, instead of inserting zeroes from the left, you insert bits that have the same value of the original sign bit.
In this way, signed divisions by 2N can be performed with just a bit of extra logic in the shift, without having to resort to a fully-fledged division routine.
Now, is arithmetic shift guaranteed for signed integers? In some languages yes1, but in C it's not like that - the behavior of the shift operators when dealing with negative integers is left as an implementation-defined detail.
As often happens, this is due to different hardware support for the operation; C is used on vastly different platforms, and, especially in the past, there was quite a difference in the "cost" of operations depending on the platform.
For example, if the processor does not provide an arithmetic right shift instruction, the compiler would be mandated to emit a much slower DIV instruction of some kind, which could be a problem in an inner loop on slower processors. For these reasons, the C standard leaves it up to the implementor to do the most appropriate thing for the current platform.
In your case, your implementation probably chose arithmetic shift because you are running on an x86 processor, that uses 2's complement arithmetic and provides both bitwise and arithmetic shift as single CPU instructions.
Actually, languages like Java even have separated arithmetic and bitwise shift operators - this is mainly due to the fact that they do not have unsigned types to e.g. store bitfields.
We've been given an assignment to make some modifications to Linux kernel code and recompile it. I'm having hard time figuring out what does this code line do:
p->time_slice = (current->time_slice + 1) >> 1;
To be more exact, why there's ">> 1" at the end?
">>" means to shift the value bitwise to the right. "x >> y" is the same as dividing by 2^y and truncating the result. Truncating the result means rounding down in almost all cases, however with negative numbers there may exist alternate implementations. Please see comments if you think this is happening to you.
That's a bitwise shift operator. Treating a value as an array of bits, it shifts everything one bit to the right (towards the least significant bit). This is the equivalent of dividing by 2, rounded down, for positive numbers. Shifting is used as a quick way to divide by a power of 2; if you shift by 1 (>> 1), you are dividing by 2, if you shift by 2 (>> 2), you are dividing by 4, and so on.
For example, here are a couple of examples of how this would work, if you were using 4 bit integers:
6 >> 1
0110 -> 0011
3
7 >> 1
0111 -> 0011
3
6 >> 2
0110 -> 0001
1
For negative numbers, it is a bit more complicated. The C standard does not specify the format of negative numbers. On most modern machines, they are stored in two's complement; that is, to represent a negative number, you take the positive representation, invert every bit, and add 1. The most significant bit is then taken to indicate the sign bit. If you right shift a negative number, there are two possible interpretations; one in which you always shift a 0 into the most significant bit, one in which you shift in a matching value to what was already there, known as "sign extension."
-2 >> 1
1110 -> 0111
7
1110 -> 1111
-1
The C standard does not specify which of these interpretations an implementation must use. GCC does the more expected one, sign extension, which is equivelent to dividing by two and rounding down, just like the positive case. Note that rounding down means "towards negative infinity", not "towards zero" as you might assume.
-3 >> 1
1101 -> 1110
-2