无符号整数的位移,为什么为负

bit shift for unsigned int, why negative?

本文关键字:为什么 无符号整数      更新时间:2023-10-16

代码:

unsigned int i = 1<<31;
printf("%dn", i);

为什么输出是-2147483648,负值?


更新的问题:

#include <stdio.h>
int main(int argc, char * argv[]) {
    int i = 1<<31;
    unsigned int j = 1<<31;
    printf("%u, %un", i, j);
    printf("%d, %dn", i, j);
    return 0;
}

以上打印:

2147483648, 2147483648
-2147483648, -2147483648

那么,这是否意味着有符号 int 和无符号 int 具有相同的位值,区别在于您在将第 31 位转换为数字值时如何处理它?

>%d打印unsigned int iint版本。尝试%u unsigned int

printf("%un", i);

int main(){
    printf("%d, %u",-1,-1);
    return 0;
}

Output: -1, 4294967295

即有符号

整数的存储方式以及如何将其从无符号转换为有符号,反之亦然将对您有所帮助。遵循这个。

为了回答您的更新问题,系统如何表示它们,即在 2 的补码中(如上述情况 -1 =2's complement of 1 = 4294967295 .

使用 '

%u ' 表示unsigned int

 printf("%un", i);
......

......

对更新问题的回答:任何位序列都可以解释为有符号或无符号值。

printf("%dn", i);调用 UB。 i unsigned int,您尝试将其打印为 signed int .编写1 << 31而不是1U << 31也是未定义的。

将其打印为:

printf("%un", i);

printf("%Xn", i);

关于您更新的问题,它也出于同样的原因调用 UB(如果您使用"1U"而不是 1 ,那么因为int是用超出范围值的1U << 31初始化的。如果使用超出范围的值初始化unsigned,则会出现模算术并分配余数。对于signed行为是未定义的。

了解平台上的行为
在您的平台上,int 显示为 4 个字节。当你写一些类似 1 << 31 的东西时,它会转换为0x80000000机器上的比特模式。

现在,当您尝试将此模式打印为签名时,它会在 2s 完成系统中打印有符号解释,即 -231(AKA INT_MIN(。当您将其打印为无符号时,您会得到预期的 231 作为输出。


知识
1. 使用1U << 31代替1 << 31
2. 始终在 printf 中使用正确的打印说明符。
3. 将正确的参数类型传递给可变参数函数。
4. 发生隐式类型转换(无符号 -> 有符号、宽类型 ->窄类型(时要小心。如果可能,请完全避免此类铸件。

尝试

printf("%un", i);

通过使用%d说明符,printf 期望参数为int,并且它类型转换为int。因此,请使用%u进行unsigned int

您不是在unsigned上而是在signed int上执行移位操作。

  • 1 signed.
  • 然后,移位操作移入符号位该signed(假设int是 32 位宽(,这已经是未定义的行为
  • 然后,您将编译器认为他想要的任何值分配给unsigned
  • 然后,将unsigned打印为已签名的,同样没有定义的行为。

%u用于无符号的int。
%d 用于已签名的 int。

在您的程序输出中:

2147483648, 2147483648     (output for unsigned int)
-2147483648, -2147483648   (output for signed int )