Dr.Kameleon
Dr.Kameleon

Reputation: 22820

Unsigned Long Long out of range?

Ok, this is a weird issue :

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?

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. All tests made on Mac OS X 10.6, and compiled using Apple's LLVM Compiler 3.0

Any suggestions?

Upvotes: 9

Views: 7614

Answers (2)

Jesse Rusak
Jesse Rusak

Reputation: 57168

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.

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.

Upvotes: 4

AusCBloke
AusCBloke

Reputation: 18492

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.

From the man pages:

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.

Upvotes: 22

Related Questions