无符号长整型溢出错误?

3

我一直遇到unsigned long long的一些奇怪问题。

当我设置一个unsigned long long(我使用了size_t,但是这个问题在u-l-l上也可以重复出现)时,它会被设置为2^31,但是由于某种原因,它会恢复到18446744071562067968,即2^64 - 2^31。请注意,我正在使用x64编译:

unsigned long long a = 1 << 31;
cout << a;

//Outputs 18446744071562067968, Expected 2147483648

我认为u-l-l的极限是2^64-1?那么为什么不能存储2^31?2^30可以正常工作。如果我没有错,sizeof(a)返回8,这是64位,证明了2^64-1的限制。

我正在Visual C++ 2013 Express Desktop上编译。

我的唯一猜测是它是某种类型的溢出错误,因为它不适合普通的长整型。


提示:1<<31 是一个 int 表达式。不是 long,也不是 unsigned。 - n. m.
谢谢,那解释了限制……那么还有另一种方法可以对long long执行二进制操作吗? - Dude Dude
1ULL << 31,例如 - rici
注意:1 << 31 会导致未定义的行为(如果 int 是32位)。虽然它在常见的实现中产生 INT_MIN,但这并不保证。 - M.M
1
需要记住的是,表达式(包括子表达式)的类型通常由表达式本身而不是出现上下文来确定。 - Keith Thompson
显示剩余3条评论
1个回答

2

您看到的是符号扩展,当负整数值被分配给无符号长整型时。

要解决这个问题,您需要一开始就将值设置为无符号的,类似于这样:

#include <iostream>
#include <iomanip>

int main()
{
    unsigned long long a = 1ull << 31ull;
    std::cout << a << "\n";
    std::cout << std::hex << a << "\n";

    return 0;
}

如果你将警告级别设置得足够高(/W4),你会看到有一个有关有符号/无符号不匹配的警告。
完整起见,你不需要同时标注两个参数,只有左操作数就可以了,所以“unsigned long long a = 1u << 31;”可以正常工作。我只是更喜欢尽可能明确。

OP的原始代码在g++中没有警告;也许Microsoft不同。 - James King
没有警告对我来说没关系...不过还是谢谢你的帮助。 - Dude Dude
这是在Visual Studio中的4级警告,因此可能您将警告设置得更低。我认为您需要使用-Wconversion才能在gcc中看到警告。 - Retired Ninja
关于“只需要一个就可以”的问题,不完全正确;左操作数必须有后缀。 - M.M
@MattMcNabb 谢谢。我已经添加了。 - Retired Ninja
显示剩余2条评论

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