I want to reset the 31st bit (last bit, 0 to 31 range) of int32_t, only this case seems to fail. ie, Output failed for the case when 'i' is 31, it's returning -1. What is the error and how do I resolve this?
#include <stdio.h>
#include <stdlib.h>
void Release(int ResetBit, int32_t *Val)
{
int32_t testBit = 1; /* XoR Bit */
if (ResetBit >= 0 && ResetBit < 32)
{
testBit = (testBit << ResetBit);
*Val ^= testBit;
}
else
{
perror("Max range is 0-31 only, failed! ");
//exit(1);
}
}
int main(int argc, char const *argv[])
{
int count = 0;
for (int i = 0; i < 32; i++)
{
int32_t MaxValue = 2147483647;
Release(i, &MaxValue);
printf("MaxValue = %d NodeID = % d\n", MaxValue, i);
count++;
}
printf("%d", count);
return 0;
}
Output for the case i = 31 is:
MaxValue = -1 NodeID = 31
First of all: Don't use signed integers for bitmaps. Always use unsigned . The reason for that is that bit shifting on signed integers may result in undefined behavior while shifting unsigned integers are always safe.
Secondly: You are using XOR in the Release
function. XOR with testBit
will not clear a bit. XOR will toggle the bit value, ie 1 becomes 0 and 0 becomes 1. Instead you want: *Val &= ~testBit;
It works like:
If testBit is 0000.0000.0000.0000.0000.0000.0000.1000
then ~testbit is 1111.1111.1111.1111.1111.1111.1111.0111
then *Val &= ... will clear bit number 3 and keep all other unchanged
as `&` is a bitwise AND operation.
When using unsigned remember to change the printf
to print an unsigned instead of using %d
, ie like printf("%" PRIu32 "\\n", uint32t_variable);
.
EDIT
What went wrong with the XOR?
Let's assume that you are using uint32_t
and XOR, then this will happen:
Your input is
0111.1111.1111.1111.1111.1111.1111.1111
and you XOR with
1000.0000.0000.0000.0000.0000.0000.0000
which toggles bit 31 resulting in
1111.1111.1111.1111.1111.1111.1111.1111
The function was supposed to clear bit 31 but it didn't. XOR is just not the correct operator for that.
If you don't need an actual signed type, use uint32_t
and all problems will go away. The problem with using bitwise operators on signed types is various forms of poorly-defined behavior.
For example, left-shifting something into the sign bit of a int32_t
leads to undefined behavior, meaning a potential bug in case your compiler doesn't cover that case with a non-standard extension. Similarly, right-shifting a negative number can either lead to arithmetic or logic shift, the C standard doesn't specify which one, but allows both forms.
That being said, if you simply wish to set/clear bit 31 of an int32_t
, it's well-defined to do so like this:
int32_t i32 = ...;
i32 |= 1u << 31; // set MSB
i32 &= ~(1u << 31); // clear MSB
i32 ^= 1u << 31; // toggle MSB
Where the u
is ensuring unsigned arithmetic.
Use the correct bitwise operation. to reset bit use &
int32_t ResetBit(int bit, int32_t *val)
{
uint32_t mask = ~(1UL << bit);
*val &= mask;
return *val;
}
and usage:
void printnitd(int32_t val)
{
for(uint32_t mask = 1UL << 31; mask; mask >>= 1)
{
printf("%c", (val & mask) ? '1' : '0');
}
}
int main(void)
{
for(int bit = 0; bit < 32; bit++)
{
int32_t a = -1;
printf("bit %u = ", a);
printnitd(ResetBit(bit, &a));
printf("\n");
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.