按位取反后右移导致意外结果

24

我本以为下面的代码会输出10,因为 (~port) 等于 10100101。 所以,当我们将其右移 4 位时,我们得到了 00001010,也就是 10。 但是结果却是 250!为什么呢?

int main()
{
    uint8_t port = 0x5a;
    uint8_t result_8 =  (~port) >> 4;
    //result_8 = result_8 >> 4;

    printf("%i", result_8);

    return 0;
}
1个回答

31

C在执行操作之前将uint8_t提升为int。所以:

  1. port被提升为有符号整数0x0000005a
  2. ~取反得到0xffffffa5
  3. 算术移位返回0xfffffffa
  4. 它再次被截断为uint8_t,得到0xfa == 250

要解决这个问题,可以截断临时结果:

uint8_t result_8 = (uint8_t)(~port) >> 4;

掩盖它:

uint8_t result_8 = (~port & 0xff) >> 4;

或者异或它(感谢@Nayuki!):

uint8_t result_8 = (port ^ 0xff) >> 4;

你说得没错,但我认为C语言不仅支持uint8_t,还支持unsigned char,因为我也用unsigned char测试过,并得到了相同的结果!我是对的吗? - Islam Abdeen
14
在你的系统上,uint8_t很可能是unsigned char的同义词。提升规则适用于所有小于int的整数类型。 - Yakov Galka
7
或者只显式地翻转低8位: result = (port ^ 0xFF) >> 4; - Nayuki
C++ 也可以做到这个吗? - Tomáš Zato
3
@TomášZato:是的。请参见https://en.cppreference.com/w/cpp/language/implicit_conversion#Numeric_promotions。 - Yakov Galka
算术位移会返回0xfffffffa,这是由具体实现定义的。参考C11dr §6.5.7 5。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接