I'm trying to shift the variable 'a' that has a value 1111 and shift it to the left so I could get 1110 meaning it should print the number 14. However, it is printing 30. I'm thinking that because it is shifting but it doesn't take the most left bit out (11110) but it should have been 1110. Here is my code. Thank you.
int main(int argc, char *argv[]) {
unsigned a;
a=0xF;
a=a<<1;
printf(": %u\n",a);
Your a variable is declared as unsigned -- this means it is an unsigned int, which usually has 32 bits. So when you put 0xF into it, it really contains 0x0000000F, or
00000000000000000000000000001111
in binary.
When you shift that one position to the left, it contains
00000000000000000000000000011110
or 30 in decimal. (0x1e in hex)
If you want to restrict it to just 4 bits, you'll want to AND the result with 0xF after every shift operation, like
a = a << 1;
a = a & 0xF;
That will result in a containing just 1110 (but really containing 00000000000000000000000000001110)
First of all, unsigned is short for unsigned int and on most modern systems, an int is defined to be 4 bytes (32 bits). In any case, it's certainly more than 4 bits.
You are right in that "it doesn't take the most left bit out".
If you want you can bitwise & it with 0xF which will set any bits to the left of the last 4 bits to 0.
a = (a << 1) & 0xF;
When you left shift a number the left most bit is not dropped it just moves to the left. So, when you left shift 1111 you will get 11110. For convenience, you can remember that whenever you left shift a number it is multiplied by 2 and when you right shift it you are in fact dividing it by 2.The drop would occur only if the type of bits that you have assigned run out for that number. In this case you will get garbage values as an answer. So your output is correct in context with what you are doing. But if you want to get 14 from 15, I suggest you use subtraction.
Shifting 1111 to the left would result in 11110, which is indeed 30. Try reading this really good answer to a related question, I Think you got the wrong idea of bit shifting.
What are bitwise shift (bit-shift) operators and how do they work?
Related
There is a 2 byte packet. The first 5 bits represent the version, the next 5 bits represent the type, and the last 6 bits represent the value. I am passing the packet as a char* to a function (print_pak). In that function, I want to print the version, type, and packet value. How can I do that?
void print_pak(char* pak)
{
}
You need to use bit masking and shifting for this. Also, when doing bit manipulation, I believe it's preferred to work with unsigned integer types since the binary representation of negative integers is not defined by the C standard.
void
print_pak(const unsigned char *pak)
{
unsigned char version, type, value;
version = (pak[0] >> 3);
type = ((pak[0]&0x07) << 2) + (pak[1] >> 6);
value = pak[1]&0x3f;
printf("Version = %u, Type = %u, Value = %u\n", version, type, value);
}
Here's how this works. The << and >> operators are for bit shifting. Suppose you have an unsigned char, x, which holds the bits 10111010. Shifting it right by 3 bits is done by (x >> 3) (operator precedence always trips me up when doing bit manipulation so I throw in parentheses to be safe). The right three bits can't go anywhere and so they fall off. The result is 00010111. Shifting to the left works the same (sort of).
Bit masking, &, implements binary "and". That is, if x is 10101011 and y is 00011111, then x&y only has 1's where x and y share them. So, it would be 00001011.
Let's take all of this and tackle your problem. The version is the first five bits of the first byte. Therefore, we want to right shift the low three bits off.
The type is the last three bits of the first byte followed by the first two bits of the second byte. That first group can be acquired by masking off the high five bits of the first byte (0x07 is 00000111 in binary). The second group can be acquired by right shifting the second byte by six bits. Then, to put them together, you need to left shift the first group by two bits to make room for the second group.
Finally, the value is the low six bits of the second byte which can be acquired by a simple masking of those bits (0x3f is 00111111 in binary).
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.
In case of unsigned short I shifted 383 by 11 positions towards left and again in the same instruction shifted it by 15 positions right, I expected the value to be 1 but it was 27. But when I used both the shift operations in different instructions one after another(first left shift and then right), output was 1.
here is a sample code :-
unsigned short seed = 383;
printf("size of short: %d\n",sizeof(short));
unsigned short seedout,seed1,seed2,seed3,seedout1;
seed1 = (seed<<11);
seed2 = (seed1>>15);
seed3 = ((seed<<11)>>15);
printf("seed1 :%d\t seed2: %d\t seed3: %d\n",seed1,seed2,seed3);
and its output was :
size of short: 2
seed1 :63488 seed2: 1 seed3: 23
seedout1: 8 seedout :382
Process returned 0 (0x0) execution time : 0.154 s
For clarity, you compare
unsigned short seed1 = (seed<<11);
unsigned short seed2 = (seed1>>15);
on one hand and
unsigned short seed3 = ((seed<<11)>>15);
on the other hand.
The first one takes the result of the shift operation, stores it in an unsigned short variable (which apparently is 16 bit on your platform) and shifts this result right again.
The second one shifts the result immediately.
The reason why this is different resp. the bits which are shifted out to the left are retained is the following:
Although seed is unsigned short, seed<<11 is signed int. Thus, these bits are not cut off as it is the case when storing the result, but they are kept in the intermediate signed int. Only the assignment to seed1 makes the value unsigned short, which leads to a clipping of the bits.
In other words: your second example is merely equivalent to
int seed1 = (seed<<11); // instead of short
unsigned short seed2 = (seed1>>15);
Regarding left shifting, type signedness & implicit promotion:
Whenever something is left shifted into the sign bit of a signed integer type, we invoke undefined behavior. Similarly, we also invoke undefined behavior when left-shifting a negative value.
Therefore we must always ensure that the left operand of << is unsigned. And here's the problem, unsigned short is a small integer type, so it is subject to implicit type promotion whenever used in an expression. Shift operators always integer promote the left operand:
C17 6.5.7:
The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand.
(This makes shifts in particular a special case, since they don't care about the type of the right operand but only look at the left one.)
So in case of a 16 bit system, you'll run into the case where unsigned short gets promoted to unsigned int, because a 16 bit int cannot hold all values of a 16 bit unsigned short. And that's fine, it's not a dangerous conversion.
On a 32 bit system however, the unsigned short gets promoted to int which is signed. Should you left shift a value like 0x8000 (MSB) set 15 bits or more, you end up shifting data into the sign bit of the promoted int, which is a subtle and possibly severe bug. For example, this prints "oops" on my Windows computer:
#include <stdio.h>
int main (void)
{
unsigned short x=0x8000;
if((x<<16) < 0) ) // undefined behavior
puts("oops");
}
But the compiler could as well have assumed that a left shift of x can never result in a value < x and removed the whole machine code upon optimization.
We need to be sure that we never end up with a signed type by accident! Meaning we must know how implicit type promotion works in C.
As for left-shifting unsigned int or larger unsigned types, that's perfectly well-defined as long as we don't shift further than the width of the (promoted) type itself (more than 31 bits on a 32 bit system). Any bits shifted out well be discarded, and if you right shift, it will always be a logical shift where zeroes are shifted in from the right.
To answer the actual question:
Your unsigned short is integer promoted to an int on a 32 bit system. This allows to shift beyond the 16 bits of an unsigned short, but if you discard those extra bits by saving the result in an unsigned short, you end up with this:
383 = 0x17F
0x17f << 11 = 0xBF800
0xBF800 truncated to 16 bits = 0xF800 = 63488
0xF800 >> 15 = 0x1
However, if skipping the middle step truncation to 15 bits, you have this instead:
0xBF800 >> 15 = 0x17 = 23
But again, this is only by luck since this time we didn't end up shifting data into the sign bit.
Another example, when executing this code, you might expect to get either the value 0 or the value 32768:
unsigned short x=32768;
printf("%d", x<<16>>16);
But it prints -32768 on my 2's complement PC. The x<<16 invokes undefined behavior, and the >>16 then apparently sign extended the result.
These kind of subtle shift bugs are common, particularly in embedded systems. A frightening amount of all C programs out there are written by people who didn't know about implicit promotions.
I shifted 383 by 11 positions towards left and again in the same instruction shifted it by 15 positions right, I expected the value to be 1 but it was 27
Simple math, you've shifted it 4 bits to the right, which is equivalent to dividing by 16.
Divide 383 by 16, and you get 27 (integer-division, of course).
Note that the "simply shifted it 4 bits" part holds because:
You've used an unsigned operand, which means that you did not "drag 1s" when shifting right
The shift-left operation likely returns an unsigned integer (32 bits) on your platform, so no data was loss during that part.
BTW, with regards to the 2nd bullet above - when you do this in parts and store the intermediate result into an unsigned short, you do indeed lose data and get a different result.
In other words, when doing seed<<11, the compiler uses 32-bit operations, and when storing it into seed1, only the LSB part of the previous result is preserved.
EDIT:
27 above should be 23. I copied that from your description without checking, though I see that you did mention 23 further down your question, so I'm assuming that 27 was a simple typo...
I am going through 'The C language by K&R'. Right now I am doing the bitwise section. I am having a hard time in understanding the following code.
int mask = ~0 >> n;
I was playing on using this to mask n left side of another binary like this.
0000 1111
1010 0101 // random number
My problem is that when I print var mask it still negative -1. Assuming n is 4. I thought shifting ~0 which is -1 will be 15 (0000 1111).
thanks for the answers
Performing a right shift on a negative value yields an implementation defined value. Most hosted implementations will shift in 1 bits on the left, as you've seen in your case, however that doesn't necessarily have to be the case.
Unsigned types as well as positive values of signed types always shift in 0 bits on the left when shifting right. So you can get the desired behavior by using unsigned values:
unsigned int mask = ~0u >> n;
This behavior is documented in section 6.5.7 of the C standard:
5 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.
Right-shifting negative signed integers is an implementation-defined behavior, which is usually (but not always) filling the left with ones instead of zeros. That's why no matter how many bits you've shifted, it's always -1, as the left is always filled by ones.
When you shift unsigned integers, the left will always be filled by zeros. So you can do this:
unsigned int mask = ~0U >> n;
^
You should also note that int is typically 2 or 4 bytes, meaning if you want to get 15, you need to right-shift 12 or 28 bits instead of only 4. You can use a char instead:
unsigned char mask = ~0U;
mask >>= 4;
In C, and many other languages, >> is (usually) an arithmetic right shift when performed on signed variables (like int). This means that the new bit shifted in from the left is a copy of the previous most-significant bit (MSB). This has the effect of preserving the sign of a two's compliment negative number (and in this case the value).
This is in contrast to a logical right shift, where the MSB is always replaced with a zero bit. This is applied when your variable is unsigned (e.g. unsigned int).
From Wikipeda:
The >> operator in C and C++ is not necessarily an arithmetic shift. Usually it is only an arithmetic shift if used with a signed integer type on its left-hand side. If it is used on an unsigned integer type instead, it will be a logical shift.
In your case, if you plan to be working at a bit level (i.e. using masks, etc.) I would strongly recommend two things:
Use unsigned values.
Use types with specific sizes from <stdint.h> like uint32_t
I'm not so good with bitwise operators so please excuse the question but how would I clear the lower 16 bits of a 32-bit integer in C/C++?
For example I have an integer: 0x12345678 and I want to make that: 0x12340000
To clear any particular set of bits, you can use bitwise AND with the complement of a number that has 1s in those places. In your case, since the number 0xFFFF has its lower 16 bits set, you can AND with its complement:
b &= ~0xFFFF; // Clear lower 16 bits.
If you wanted to set those bits, you could instead use a bitwise OR with a number that has those bits set:
b |= 0xFFFF; // Set lower 16 bits.
And, if you wanted to flip those bits, you could use a bitwise XOR with a number that has those bits set:
b ^= 0xFFFF; // Flip lower 16 bits.
Hope this helps!
To take another path you can try
x = ((x >> 16) << 16);
One way would be to bitwise AND it with 0xFFFF0000 e.g. value = value & 0xFFFF0000
Use an and (&) with a mask that is made of the top 16 bit all ones (that will leave the top bits as they are) and the bottom bits all zeros (that will kill the bottom bits of the number).
So it'll be
0x12345678 & 0xffff0000
If the size of the type isn't known and you want to mask out only the lower 16 bits you can also build the mask in another way: use a mask that would let pass only the lower 16 bits
0xffff
and invert it with the bitwise not (~), so it will become a mask that kills only the lower 16 bits:
0x12345678 & ~0xffff
int x = 0x12345678;
int mask = 0xffff0000;
x &= mask;
Assuming the value you want to clear bits from has an unsigned type not of "small rank", this is the safest, most portable way to clear the lower 16 bits:
b &= -0x10000;
The value -0x10000 will be promoted to the type of b (an unsigned type) by modular arithmetic, resulting in all high bits being set and the low 16 bits being zero.
Edit: Actually James' answer is the safest (broadest use cases) of all, but the way his answer and mine generalize to other similar problems is a bit different and mine may be more applicable in related problems.