超出范围的无符号长整型?

9

嗯,这是一个奇怪的问题:

  • 我正在使用unsigned long long变量(我甚至使用了相同效果的long变量)
  • 需要能够存储64位整数(sizeof返回8,这很好)

然而,当我尝试达到像1<<63这样的值,并执行一些简单的位运算时,我会奇怪地得到负值。为什么呢?

我的测试代码:

    unsigned long long c = 0;

    c |= 1l << 56; printf("c = %lld\n",c);
    c |= 1l << 63; printf("c = %lld\n",c);

输出:

c = 72057594037927936 
c = -9151314442816847872

注:

  1. 当然,即使我直接执行 c = 1l<<63,也会发生同样的事情。
  2. 所有测试均在Mac OS X 10.6上进行,并使用Apple的LLVM编译器3.0进行编译。

有什么建议吗?


1
如果您需要64位整数,您可能更喜欢使用uint64_t。 - Jesse Rusak
我知道你已经选择了一个答案,但我还有一个问题:你是在编译64位核心吗?sizeof(long)是多少?我很惊讶1l<<63能够工作,因为我认为它会将32位的1l向左移动63位,使你得到一个值为零。但如果sizeof(long)也是8,也许这就是它能够工作的原因。如果我是正确的,那么Jesse Rusak的答案就有一定的道理,尽管那个答案不能解决你的问题。 - phonetagger
2
是的,1l 应该改为 1ull 以确保它至少有 64 位长。 - AusCBloke
2个回答

22
%lld 格式中的 d 部分告诉 printf 函数参数应被视为带符号整数。请使用 u 替代:%llu
参考手册中如下解释: d, i The int argument is converted to signed decimal notation. o, u, x, X The unsigned int argument is converted to unsigned octal (o), unsigned decimal (u), or unsigned hexadecimal (x and X) notation.

好的,现在是那种经过大量思考和多层调试努力后,我感觉自己像个白痴的时候之一...哈哈。我想我学到了非常有价值的东西。(当然,这个问题影响的不仅仅是一个两行代码的测试)。非常感谢你,伙计!你肯定为我节省了很多时间!;-) - Dr.Kameleon
2
@Dr.Kameleon:别担心,这种事情每个人都会遇到。 - AusCBloke

4
我认为你在这里实际上做了一些未定义的事情。我认为表达式1l << 63在C语言中是未定义的,因为编译器会将1l表示为有符号类型,并且将其向左移动63位会导致有符号溢出(在C语言中是未定义的)。虽然我不是专家,但似乎你想要1ull << 63
事实上,如果你在clang中传递-Weverything,你的原始代码会抱怨这个问题:
foo.c:7:23: warning: signed shift result (0x8000000000000000) sets the sign bit of the
            shift expression's type ('long') and becomes negative [-Wshift-sign-overflow]
      c |= 1l << 63; printf("c = %lld\n",c);
           ~~ ^  ~~

编辑:是的,然后你需要来自另一个回答的正确printf格式。

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