无符号Long Long超出范围?

时间:2020-12-08 19:16:28

Ok, this is a weird issue :

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

  • I'm using unsigned long long variables (I've used even long ones, with the same effect)
  • 我正在使用无符号长long变量(我甚至使用了长变量,具有相同的效果)

  • I need to be able to store 64-bit integers (sizeof returns 8, which is fine)
  • 我需要能够存储64位整数(sizeof返回8,这很好)

However, when I'm trying to go to values like 1<<63, and perform some simple bitwise operations, I - oddly - seem to be getting negative values. Why's that?

然而,当我试图去像1 << 63这样的值,并执行一些简单的按位运算时,奇怪的是 - 我似乎得到负值。为什么?

My test code :

我的测试代码:

    unsigned long long c = 0;

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

Output :

c = 72057594037927936 
c = -9151314442816847872

Sidenotes :

  1. Of course, same thing happens even if I do c = 1l<<63 directly.
  2. 当然,即使我直接做c = 1l << 63,也会发生同样的事情。

  3. All tests made on Mac OS X 10.6, and compiled using Apple's LLVM Compiler 3.0
  4. 所有测试均在Mac OS X 10.6上进行,并使用Apple的LLVM编译器3.0进行编译


Any suggestions?

2 个解决方案

#1


22  

The d part of the %lld specifier is telling printf that the argument should be treated as a signed integer. Use a u instead: %llu.

%lld说明符的d部分告诉printf该参数应该被视为有符号整数。请改用u:%llu。

From the man pages:

从手册页:

d, i

The int argument is converted to signed decimal notation.

int参数转换为带符号的十进制表示法。

o, u, x, X

o,u,x,X

The unsigned int argument is converted to unsigned octal (o), unsigned decimal (u), or unsigned hexadecimal (x and X) notation.

unsigned int参数转换为无符号八进制(o),无符号十进制(u)或无符号十六进制(x和X)表示法。

#2


4  

I think you're actually doing something undefined here. I think the expression 1l << 63 is undefined in C, since the compiler will represent 1l in a signed type, and shifting by 63 bits causes an signed overflow (which is undefined in C). I'm not an expert, but seems like you want 1ull << 63.

我想你实际上是在做一些未定义的事情。我认为表达式1l << 63在C中是未定义的,因为编译器将在有符号类型中表示1l,并且移位63位会导致有符号溢出(在C中未定义)。我不是专家,但似乎你想要1个<< 63。

Your original code, in fact, complains about this if you pass -Weverything in clang:

事实上,你的原始代码如果你传递了一切,就会抱怨这个:

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);
           ~~ ^  ~~

EDIT: And, yes, then you need the correct printf format from the other answer.

编辑:是的,那么你需要从另一个答案正确的printf格式。

#1


22  

The d part of the %lld specifier is telling printf that the argument should be treated as a signed integer. Use a u instead: %llu.

%lld说明符的d部分告诉printf该参数应该被视为有符号整数。请改用u:%llu。

From the man pages:

从手册页:

d, i

The int argument is converted to signed decimal notation.

int参数转换为带符号的十进制表示法。

o, u, x, X

o,u,x,X

The unsigned int argument is converted to unsigned octal (o), unsigned decimal (u), or unsigned hexadecimal (x and X) notation.

unsigned int参数转换为无符号八进制(o),无符号十进制(u)或无符号十六进制(x和X)表示法。

#2


4  

I think you're actually doing something undefined here. I think the expression 1l << 63 is undefined in C, since the compiler will represent 1l in a signed type, and shifting by 63 bits causes an signed overflow (which is undefined in C). I'm not an expert, but seems like you want 1ull << 63.

我想你实际上是在做一些未定义的事情。我认为表达式1l << 63在C中是未定义的,因为编译器将在有符号类型中表示1l,并且移位63位会导致有符号溢出(在C中未定义)。我不是专家,但似乎你想要1个<< 63。

Your original code, in fact, complains about this if you pass -Weverything in clang:

事实上,你的原始代码如果你传递了一切,就会抱怨这个:

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);
           ~~ ^  ~~

EDIT: And, yes, then you need the correct printf format from the other answer.

编辑:是的,那么你需要从另一个答案正确的printf格式。