右移 unsigned char 是用 ones 填充的吗?

right-shifting unsigned char is filling with ones?

在我的系统上,(unsigned char) -1 是(预计为 8 位字符)1111 1111 二进制(255 十进制)。

同理,(unsigned char) -1 >> 1也是0111 1111,左边补了个零。

~((unsigned char) -1 >> 1) 是预期的 1000 0000。

现在我想生成 unsigned char 0010 0000 例如。

我试过 ~((unsigned char) -1 >> 1) >> 2,但是输出 1110 0000 ....什么?怎么左边突然全是1了?


如何生成启用第 n 位(从左起)的 unsigned char

我愿意

n   unsigned char
0   1000 0000
1   0100 0000
2   0010 0000
3   0001 0000
... 
7   0000 0001

此刻,~((unsigned char) -1 >> 1) >> n给我

n   unsigned char
0   1000 0000
1   1100 0000
2   1110 0000
3   1111 0000
... 
7   1111 1111

此问题存在于 uint8_tuint16_t,但不再发生在 uint32_t 及更高版本。

由于整数提升,当几乎对值执行任何操作时,unsigned char 被提升为 int

当您右移时,左操作数会进行整数提升,unsigned char 将变为 int。表达式的值将是提升后左操作数的值 - 因此 ((unsigned char) -1 >> 1) 的结果值为 127,类型为 int。如果你 ~ (int)127 你会得到一个设置了符号位的 int;向右移动将具有实​​现定义的行为。

解决方法是在around外加一个cast ~:

(unsigned char)~((unsigned char) -1 >> 1) >> 2

或者,& 0xFF 的值:

(~((unsigned char) -1 >> 1) >> 2) & 0xFF

关于设置[=12=左起第n位,最好的解决办法是*左移1U到位置,如.

设置第n位(左起)的另一种方法:

1 << (CHAR_BIT - n - 1)

您可以利用 std::numeric_limits<T>::digits 创建一个不那么混淆和灵活的代码:

    unsigned char data=0;
    
    const uint8_t sizeBit=std::numeric_limits<decltype(data)>::digits;
    for(uint8_t n=0;n<sizeBit;n++) {
        data = 1 << (sizeBit - (n+1));
        std::bitset<sizeBit> x(data);
        std::cout << x << '\n';
    }

打印:

10000000
01000000
00100000
00010000
00001000
00000100
00000010
00000001