2012-12-10 16 views
9

Ok, đây là một vấn đề kỳ lạ:Unsigned Long Long nằm ngoài phạm vi?

  • Tôi đang sử dụng unsigned long long biến (Tôi đã sử dụng ngay cả long người, với tác dụng tương tự)
  • tôi cần để có thể lưu trữ 64 số nguyên bit (sizeof lợi nhuận 8, đó là tốt)

Tuy nhiên, khi tôi đang cố gắng để đi đến giá trị như 1<<63, và thực hiện một số hoạt động Bitwise đơn giản, tôi - kỳ quặc - dường như nhận được giá trị âm. Tại sao vậy?

mã kiểm tra của tôi:

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. Tất nhiên, điều tương tự cũng xảy ra ngay cả khi tôi thực hiện trực tiếp c = 1l<<63.
  2. Tất cả các bài kiểm tra được thực hiện trên Mac OS X 10.6, và biên soạn sử dụng của Apple LLVM Compiler 3,0

Bất kỳ lời đề nghị?

+1

Nếu bạn cần * số nguyên 64 bit, bạn có thể thích sử dụng uint64_t. –

+0

Tôi biết bạn đã chọn câu trả lời nhưng tôi vẫn có câu hỏi: Bạn có đang biên soạn lõi 64 bit không? 'Sizeof (long)' là gì? Tôi ngạc nhiên rằng '1l << 63' hoạt động, vì tôi đã nghĩ rằng nó sẽ chuyển một bit 32 bit 1l' lên 63 bit, để lại cho bạn một giá trị bằng không. Nhưng nếu 'sizeof (long)' cũng là 8, có lẽ đó là lý do tại sao nó hoạt động. Nếu tôi đúng, thì có một số sự thật với câu trả lời của Jesse Rusak, mặc dù câu trả lời đó không giải quyết được vấn đề của bạn. – phonetagger

+2

Yeah '1l' thực sự nên là' 1ull' để đảm bảo rằng nó dài ít nhất 64 bit. – AusCBloke

Trả lời

22

Phần d của thông số %lld đang cho biết printf rằng đối số sẽ được coi là số nguyên đã ký. Sử dụng số u thay thế: %llu.

Từ trang người đàn ông:

d, i

Đối số int được chuyển thành ký hiệu thập phân.

o, u, x, X

Đối số int unsigned được chuyển thành unsigned bát phân (o), unsigned thập phân (u), hoặc unsigned thập lục phân (x và ký hiệu X).

+0

OK, bây giờ là một trong những thời điểm đó, khi sau nhiều lần trầy xước và ... những nỗ lực gỡ lỗi đa cấp, tôi cảm thấy như một thằng ngốc ... lol. Đoán tôi đã học được một cái gì đó thực sự có giá trị. (Tất nhiên vấn đề đã ảnh hưởng đến thứ gì đó lớn hơn rất nhiều ... và không chỉ là thử nghiệm 2 lớp). Cảm ơn rất nhiều, bạn thân! Bạn chắc chắn đã cứu tôi rất nhiều thời gian! ;-) –

+1

@ Dr.Kameleon: Đừng lo lắng, xảy ra với mọi người. – AusCBloke

4

Tôi nghĩ rằng bạn đang thực sự làm một cái gì đó không xác định ở đây.Tôi nghĩ rằng biểu thức 1l << 63 là không xác định trong C, vì trình biên dịch sẽ đại diện cho 1l trong một loại đã ký, và dịch chuyển bởi 63 bit gây ra tràn đã ký (không xác định trong C). Tôi không phải là chuyên gia, nhưng có vẻ như bạn muốn 1ull << 63.

mã ban đầu của bạn, trên thực tế, phàn nàn về điều này nếu bạn vượt qua -Weverything trong kêu vang:

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: Và, vâng, thì bạn cần phải định dạng printf đúng từ câu trả lời khác.