簡體   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