如何在 C 中使用有符号或无符号整数进行位映射?

How to use signed or unsigned integer for bit mapping in C?

我想重置int32_t的第31位(最后一位,0到31的范围),只有这种情况似乎失败了。 即,当 'i' 为 31 时输出失败,返回 -1。错误是什么?我该如何解决?

#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;
}

案例 i = 31 的输出是:

最大值 = -1 节点 ID = 31

首先:不要对位图使用有符号整数。始终使用无符号。原因是对有符号整数进行位移可能会导致未定义的行为,而对无符号整数进行位移总是安全的。

其次:您在 Release 函数中使用了 XOR。与 testBit 的 XOR 不会清除一点。 XOR 将切换位值,即 1 变为 0,0 变为 1。相反,您想要:*Val &= ~testBit; 它的工作方式如下:

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.

使用 unsigned 时记得更改 printf 以打印 unsigned 而不是使用 %d,即像 printf("%" PRIu32 "\n", uint32t_variable);.

编辑

XOR 出了什么问题?

假设您正在使用 uint32_t 和 XOR,那么会发生这种情况:

您的输入是

0111.1111.1111.1111.1111.1111.1111.1111

你与

异或
1000.0000.0000.0000.0000.0000.0000.0000

它切换位 31 导致

1111.1111.1111.1111.1111.1111.1111.1111

该函数应该清除第 31 位,但它没有。 XOR 不是正确的运算符。

如果您不需要实际的签名类型,请使用 uint32_t,所有问题都会消失。在有符号类型上使用按位运算符的问题是各种形式的 poorly-defined 行为。

例如,left-shifting int32_t 的符号位中的某些内容会导致未定义的行为,这意味着如果您的编译器未使用 [=26= 涵盖该情况,则可能存在错误] 延期。类似地,right-shifting 一个负数可以导致算术或逻辑移位,C 标准没有指定哪一种,但允许两种形式。

也就是说,如果您只是想 set/clear int32_t 的第 31 位,那么 well-defined 可以这样做:

int32_t i32 = ...;
i32 |= 1u << 31;    // set MSB
i32 &= ~(1u << 31); // clear MSB
i32 ^= 1u << 31;    // toggle MSB

其中 u 确保无符号算术。

使用正确的位运算。重置位使用 &

int32_t ResetBit(int bit, int32_t *val)
{
    uint32_t mask = ~(1UL << bit);

    *val &= mask;
    return *val;
}

和用法:

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");
    }
}