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.
Related
I am trying to figure out how exactly arithmetic bit-shift operators work in C, and how it will affect signed 32-bit integers.
To make things simple, let's say we work within one byte (8 bits):
x = 1101.0101
MSB[ 1101.0101 ]LSB
Reading other posts on Stack Overflow and some websites, I found that:
<< will shift toward MSB (to the left, in my case), and fill "empty" LSB bits with 0s.
And >> will shift toward LSB (to the right, in my case) and fill "empty" bits with MS bit
So, x = x << 7 will result in moving LSB to MSB, and setting everything to 0s.
1000.0000
Now, let's say I would >> 7, last result. This would result in [0000.0010]? Am I right?
Am I right about my assumptions about shift operators?
I just tested on my machine, **
int x = 1; //000000000......01
x = x << 31; //100000000......00
x = x >> 31; //111111111......11 (Everything is filled with 1s !!!!!)
Why?
Right shift of a negative signed number has implementation-defined behaviour.
If your 8 bits are meant to represent a signed 8 bit value (as you're talking about a "signed 32 bit integer" before switching to 8 bit examples) then you have a negative number. Shifting it right may fill "empty" bits with the original MSB (i.e. perform sign extension) or it may shift in zeroes, depending on platform and/or compiler.
(Implementation-defined behaviour means that the compiler will do something sensible, but in a platform-dependent manner; the compiler documentation is supposed to tell you what.)
A left shift, if the number either starts out negative, or the shift operation would shift a 1 either to or beyond the sign bit, has undefined behaviour (as do most operations on signed values which cause an overflow).
(Undefined behaviour means that anything at all could happen.)
The same operations on unsigned values are well-defined in both cases: the "empty" bits will be filled with 0.
Bitwise shift operations are not defined for negative values
for '<<'
6.5.7/4 [...] If E1 has a signed type and nonnegative value, and E1×2E2 is representable in the result type, then that is the resulting value; otherwise, the behavior is undefined.
and for '>>'
6.5.7/5 [...] If E1 has a signed type and a negative value, the resulting value is implementation- defined.
It's a waste of time to study the behaviour of these operations on signed numbers on a specific implementation, because you have no guarantee it will work the same way on any other implementation (an implementation is, for example, you compiler on your computer with your specific commad-line parameters).
It might not even work for an older or a newer version of the very same compiler. The compiler might even define those bits as random or undefined. This would mean that the very same code sequence could produce totally different results when used across your sources or even depend on things like assembly optimisation or other register usage. If encapsulated in a function it might not even produce the same result in those bits on two consecutive calls with the same arguments.
Considering only non-negative values, the effect of left shifting by 1 (expression << 1) is the same as multpliying the expression by 2 (provided expression * 2 does not overflow) and the effect of right shifting by 1 (expression >> 1) is the same as dividing by 2.
As of c++20 the bitwise shift operators for signed integers are well defined.
The left shift a<<b is equivalent to a*2^b modulus 2^N where N is the number of bits in the resulting type. In particular 1<<31 is in fact the smallest int value.
The right shift a>>b is equivalent to a/2^b, rounded down (ie. towards negative infinity). So e.g. -1>>10 == -1.
For some more details see https://en.cppreference.com/w/cpp/language/operator_arithmetic .
(for the older standards see the answer by Matthew Slattery)
As others said shift of negative value is implementation-defined.
Most of implementations treat signed right shift as floor(x/2N) by filling shifted in bits using sign bit. It is very convenient in practice, as this operation is so common. On the other hand if you will shift right unsigned integer, shifted in bits will be zeroed.
Looking from machine side, most implementations have two types of shift-right instructions:
An 'arithmetic' shift right (often having mnemonic ASR or SRA) which works as me explained.
A 'logic' shift right (oftem having mnemonic LSR or SRL or SR) which works as you expect.
Most of compilers utilize first for signed types and second for unsigned ones. Just for convenience.
In the 32 bit compiler
x = x >> 31;
here x is the signed integer so 32nd bit is sign bit.
final x value is 100000...000. and 32nd bit indicate -ive value.
here x value implement to 1's compliment.
then final x is -32768
On my i7:
uint64_t:
0xffffffffffffffff >> 0 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 1 is 0b0111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 2 is 0b0011111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 3 is 0b0001111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 4 is 0b0000111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 62 is 0b0000000000000000000000000000000000000000000000000000000000000011
0xffffffffffffffff >> 63 is 0b0000000000000000000000000000000000000000000000000000000000000001
0xffffffffffffffff >> 64 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 65 is 0b0111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 66 is 0b0011111111111111111111111111111111111111111111111111111111111111
int64_t -1
0xffffffffffffffff >> 0 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 1 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 2 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 3 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 4 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 62 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 63 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 64 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 65 is 0b1111111111111111111111111111111111111111111111111111111111111111
0xffffffffffffffff >> 66 is 0b1111111111111111111111111111111111111111111111111111111111111111
int64_t 2^63-1
0x7fffffffffffffff >> 0 is 0b0111111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 1 is 0b0011111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 2 is 0b0001111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 3 is 0b0000111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 4 is 0b0000011111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 62 is 0b0000000000000000000000000000000000000000000000000000000000000001
0x7fffffffffffffff >> 63 is 0b0000000000000000000000000000000000000000000000000000000000000000
0x7fffffffffffffff >> 64 is 0b0111111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 65 is 0b0011111111111111111111111111111111111111111111111111111111111111
0x7fffffffffffffff >> 66 is 0b0001111111111111111111111111111111111111111111111111111111111111
I know there is another post here that is how to clear a single bit, but how about a whole byte?
For example, if I had 00000000 00000000 00101100 11000100 and I wanted to clear the second chunk so it was now 00000000 00000000 00000000 11000100, how would I go about doing that? I know I need to use bitwise &.
To clear specific bits within a memory area you can use the bitwise And operator, &, along with a mask. To create the mask, rather than thinking of which bits you want to clear, you should instead think of which bits you want to keep and create the mask using those bits.
The mask should be the same type of variable as the type of variable stored in the memory area. So if you are wanting to clear bits in a long variable then you would create a mask in another long variable which indicates the bits you want to keep.
Assume you have a variable of type unsigned long which contains the bit pattern 00000000 00000000 00101100 11000100 and you want to clear the bits in the second byte from the right, the eight bits of 00101100 while keeping the other bits.
First you create a mask that has the bits you want to keep as in 11111111 11111111 00000000 11111111 or 0xffff00ff. If you want to clear all other bits except for the least significant byte then you could use 0xff for your mask.
Next you use the bitwise And operator & to and the variable with the mask. Many times you would use the &= operator with the variable containing the value with bits to clear on one side of the operator and the mask indicating which bits to keep on the other.
unsigned long x1 = 0x2cc4; // variable to mask.
unsigned long mask = 0xffff00ff; // mask to zero all bits in the second byte from the right
x1 &= mask; // keep only the bits we want to keep
Or you could hard code the mask as in:
unsigned long x1 = 0x2cc4;
x1 &= 0xffff00ff; // keep only the bits we want to keep
Or if you don't want to modify the original variable something like:
unsigned long x1 = 0x2cc4; // variable to mask.
unsigned long x2 = 0; // variable for new, masked value of x1
unsigned long mask = 0xffff00ff; // mask to zero all bits in the second byte from the right
x2 = x1 & mask; // keep only the bits we want to keep and put into a new variable
The bitwise And operator does an And operation on each bit and the resulting output bit for each bit is calculated using an And truth table. 0 And either 0 or 1 results in a 0 and only if both bits are 1 will a 1 result.
0 | 1
-----------
0 | 0 | 0
1 | 0 | 1
As a side note you can also set the bits you want to clear in the mask and then use the bitwise Not operator, ~, and turn the mask from a mask of bits you want to clear to a mask of bits you want to keep. However this is not the way that it is usually done so may be confusing to other programmers reading the code.
unsigned long x1 = 0x2cc4;
unsigned long mask = ~0xff00; // mask to zero all bits in the second byte from the right
x1 &= mask; // And to keep only the bits we want to keep
Note also that the C Standard is a bit loose about how many bits are actually included in the most commonly used variable types such as int, short, long, etc. There are guarantees about the minimum size but not necessarily the maximum size. This was done in order to provide backward compatibility as well as to allow portability of source code and flexibility for compilers targeting specific hardware platforms. However it means that if you depend on the implementation of int as 64 bit in source code that is then moved to 32 bit hardware you may be surprised by the behavior.
The header file stdint.h specifies a number of exact width integer types such as int8_t and others. See stdint.h — Integer types however not all compiler vendors will provide support though most up to date compilers do.
As an aside, using hard coded numeric values such as 0xff for a bit mask that is intended to be used in several places and has a specific meaning (e.g. buffer size field) is generally frowned upon. The normal practice is to use a #define macro with a descriptive label, usually within an include file if the constant is needed in multiple source files, to name the bit mask in C programs. Creating a defined constant allows there to be a single point of definition for the bit mask constant thereby providing consistency of use, it will be right everywhere or wrong everywhere. Doing this also provides a unique, searchable identifier for the bit mask constant should you need to find where it is being used. In C++ a const variable such as const unsigned long BitMaskA = 0x00ff; is normally used instead of a #define as such a variable defaults to internal linkage in C++, though it defaults to external linkage in C, and not depending on the Preprocessor is encouraged for C++ (see https://stackoverflow.com/a/12043198/1466970)
Note as well that using bitfield variable types is a different mechanism than using the bitwise operators with masks. For instance see When to use bit-fields in C? as well as this answer which talks to the portability problem https://stackoverflow.com/a/54054552/1466970
Suppose you want to clear the bits from s(start) to e(end) in the bit vector BV. And total number of bits in a number is b. Proceed as follows:
mask = ~0;
This will set all the bits. Something like 11111111
mask = mask >> (b - (e - s + 1));
This will give something like 00000111, with number of set bits equal to number of bits you want to clear.
mask = mask << s;
This will move the set bits to the desired positions. Something like 00111000
mask = ~mask;
This will give 11000111
Now perform & with the bit vector
B &= mask;
This will clear the bits from s to e.
The problem is simple:
Take an 32-bit or 64-bit integer and split it up to send over an (usually)1-byte interface like uart, spi or i2c.
To do this I can easily use bit masking and shifting to get what I want. However, I want this to be portable that will work on big and little endian, but also make it work for platforms that don't discard bits but rotate through carry(masking gets rid of excess bits right?).
Example code:
uint32_t value;
uint8_t buffer[4];
buffer[0] = (value >> 24) & 0xFF;
buffer[1] = (value >> 16) & 0xFF;
buffer[2] = (value >> 8) & 0xFF;
buffer[3] = value & 0xFF;
I want to guarantee this works on any platform that supports 32 bit integers or more. I don't know if this is correct.
The code you presented is the most portable way of doing it. You convert a single unsigned integer value with 32 bits width into an array of unsigned integer values of exactly 8 bits width. The resulting bytes in the buffer array are in big endian order.
The masking is not needed. From C11 6.5.7p5:
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 / 2^E2.
and casting to an integer with 8 bits width is (to the value) equal to masking 8 bits. So (result >> 24) & 0xff is equal to (uint8_t)(result >> 24) (to the value). As you assign to uint8_t variable the masking is not needed. Anyway I would safely assume it will be optimized out by a sane compiler.
I can recommend to take a look at one implementation that I remembered, that I guess has implemented in a really safe manner all the possible variants of splitting and composing fixed-width integers up to 64 bits from bytes and back, that is at gpsd bits.h.
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?
I am kinda new to bit operations. I am trying to store information in an int64_t variable like this:
int64_t u = 0;
for(i=0;i<44;i++)
u |= 1 << i;
for(;i<64;i++)
u |= 0 << i;
int t = __builtin_popcountl(u);
and what I intended with this was to store 44 1s in variable u and make sure that the remaining positions are all 0, so "t" returns 44. However, it always returns 64. With other variables, e.g. int32, it also fails. Why?
The type of an expression is generally determined by the expression itself, not by the context in which it appears.
Your variable u is of type int64_t (incidentally, uint64_t would be better since you're performing bitwise operations).
In this line:
u |= 1 << i;
since 1 is of type int, 1 << i is also of type int. If, as is typical, int is 32 bits, this has undefined behavior for larger values of i.
If you change this line to:
u |= (uint64_t)1 << i;
it should do what you want.
You could also change the 1 to 1ULL. That gives it a type of unsigned long long, which is guaranteed to be at least 64 bits but is not necessarily the same type as uint64_t.
__builtin_popcountl takes unsigned long as its paremeter, which is not always 64-bit integer. I personally use __builtin_popcountll, which takes long long. Looks like it's not the case for you
Integers have type 'int' by default, and by shifting int by anything greater or equal to 32 (to be precise, int's size in bits), you get undefined behavior. Correct usage: u |= 1LL << i; Here LL stands for long long.
Oring with zero does nothing. You can't just set bit to a particular value, you should either OR with mask (if you want to set some bits to 1s) or AND with mask's negation (if you want to set some bits to 0s), negation is done by tilda (~).
When you shift in the high bit of the 32-bit integer and and convert to 64-bit the sign bit will extend through the upper 32 bits; which you will then OR in setting all 64 bits, because your literal '1' is a signed 32 bit int by default. The shift will also not effect the upper 32 bits because the value is only 32 bit; however the conversion to 64-bit will when the the value being converted is negative.
This can be fixed by writing your first loop like this:
for(i=0;i<44;i++)
u |= (int64_t)1 << i;
Moreover, this loop does nothing since ORing with 0 will not alter the value:
for(;i<64;i++)
u |= 0 << i;