带有负值的无符号长整数

use*_*167 5 c++

请参阅下面的简单代码:

#include <iostream>
#include <stdlib.h>

using namespace std;


int main(void)
{
    unsigned long currentTrafficTypeValueDec;
    long input;
    input=63;
    currentTrafficTypeValueDec = (unsigned long) 1LL << input; 
    cout << currentTrafficTypeValueDec << endl;
    printf("%u \n", currentTrafficTypeValueDec);
    printf("%ld \n", currentTrafficTypeValueDec);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为什么printf()显示带负值的currentTrafficTypeValueDec(unsigned long)?

输出是:

9223372036854775808
0
-9223372036854775808 
Run Code Online (Sandbox Code Playgroud)

Mik*_*one 17

%d是一个签名格式化程序.将currentTrafficTypeValueDec(2到63次幂)的位重新解释为a signed long给出负值.所以printf()打印一个负数.

也许你想用%lu


APr*_*mer 14

你通过传递一个无符号值来欺骗printf,而格式规则说它将是一个签名的.


Mic*_*urr 5

因为你正在转移1到变量的符号位.当您将其打印为有符号值时,它是否定的.


Nea*_*alB 5

有趣的点...

cout将数字打印为无符号长整型,所有 64 位都是有效的,并打印为无符号二进制整数(我认为这里的格式是%lu)。

printf(%u ...将输入视为正常的无符号整数(32 位?)。这会导致第 33 位到第 64 位下降 - 留下零。

printf(%ld ... 将输入视为 64 位有符号数,然后将其打印出来。

您可能会对最后一个感到困惑的printf是,它给出的绝对值与 相同cout,但带有一个减号。当查看为无符号整数时,所有 64 位在生成整数值时都很重要。但是对于有符号数,第 64 位是符号位。当设置符号位时(如您的示例中所示),它表示剩余的 63 位将被视为以2 的补码表示的负数. 正数只需将其二进制值转换为十进制即可打印出来。但是,对于负数,会发生以下情况:打印负号,将 1 到 63 位与二进制“1”位进行异或,将结果加 1 并打印无符号值。通过删除符号位(第 64 位),您最终得到 63 个“0”位,与“1”位进行异或得到 63 个“1”位,加上 +1,整个过程翻转为您提供一个具有位的无符号整数64 设置为“1”,其余设置为“0” - 这与您使用coutBUT得到的相同,作为负数。

一旦你弄清楚为什么上述解释是正确的,你也应该能够理解这一点