繁体   English   中英

如何在 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 的输出是:

MaxValue = -1 NodeID = 31

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

其次:您在Release函数中使用 XOR。 testBit异或不会清除一点。 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并且所有问题都会消失。 在有符号类型上使用按位运算符的问题是各种形式的定义不明确的行为。

例如,将某些内容左移到int32_t的符号位会导致未定义的行为,这意味着一个潜在的错误,以防您的编译器没有使用非标准扩展覆盖这种情况。 类似地,右移负数可以导致算术或逻辑移位,C 标准没有指定哪一种,但允许两种形式。

话虽如此,如果您只是想设置/清除int32_t 31 位,那么这样做是明确定义的:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM