2012-12-10 12 views
9

Ok, to jest dziwny problem:Unsigned Long Long poza zakresem?

  • Używam unsigned long long zmiennych (Użyłem nawet long te, z tym samym skutkiem)
  • muszę aby móc przechowywać 64- bitowe liczby całkowite (sizeof powraca 8, co jest w porządku)

jednak, gdy staram się iść do wartości jak 1<<63 i wykonać kilka prostych czynności bitowe, i - dziwnie - wydają się być coraz wartości ujemne. Dlaczego tak jest?

Mój kod testowy:

unsigned long long c = 0; 

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

wyjściowa:

c = 72057594037927936 
c = -9151314442816847872 

Sidenotes:

  1. Oczywiście, to samo dzieje się, nawet jeśli wykonuję c = 1l<<63 bezpośrednio.
  2. Wszystkie testy wykonane w systemie Mac OS X 10.6 i skompilowany przy użyciu kompilatora LLVM Apple 3,0

sugestie?

+1

Jeśli * potrzebujesz * 64-bitowych liczb całkowitych, możesz użyć uint64_t. –

+0

Wiem, że już wybrałeś odpowiedź, ale wciąż mam pytanie: Czy kompilujesz 64-bitowy rdzeń? Co to jest "sizeof (long)"? Jestem zaskoczony, że '1l << 63' działa, jak bym pomyślał, że przesunie 32-bitowe' 1l' w górę o 63 bity, pozostawiając ci wartość zero. Ale jeśli 'sizeof (long)' to także 8, może dlatego działa. Jeśli mam rację, odpowiedź Jessego Rusaka jest trochę prawidłowa, nawet jeśli ta odpowiedź nie rozwiązałaby twojego problemu. – phonetagger

+2

Tak, '1l' naprawdę powinno być' 1ull', aby zagwarantować, że ma on co najmniej 64 bity. – AusCBloke

Odpowiedz

22

Część specyfikatora mówi printf, że argument powinien być traktowany jako liczba całkowita ze znakiem. Zamiast tego należy użyć u: %llu.

Od strony podręcznika:

d,

int argumentem jest konwertowany do podpisał notacji dziesiętnej.

O, U, X, X

unsigned int argumentu jest przekształcany unsigned ósemkowej (O) unsigned przecinku (U) lub unsigned szesnastkowe (x i X) notacja.

+0

OK, teraz jest jeden z tych czasów, kiedy po wielu próbach wyłudzenia głowy i ... wielopoziomowych debugowaniu, czuję się jak idiota ... lol. Chyba nauczyłem się czegoś naprawdę cennego. (Oczywiście problem dotyczył czegoś o wiele większego ... a nie tylko testu 2-liniowego). Wielkie dzięki, kolego! Zdecydowanie zaoszczędziłeś mi dużo czasu! ;-) –

+1

@ Dr.Kameleon: Nie martw się, zdarza się każdemu. – AusCBloke

4

Myślę, że faktycznie robisz coś nieokreślonego tutaj.Myślę, że wyrażenie 1l << 63 jest niezdefiniowane w C, ponieważ kompilator będzie reprezentował 1l w podpisanym typie, a przesuwanie o 63 bity powoduje podpisane przepełnienie (które jest niezdefiniowane w C). Nie jestem ekspertem, ale wygląda na to, że chcesz 1ull << 63.

Twój oryginalny kod, w rzeczywistości, narzeka na to, czy zdasz -Weverything w brzękiem:

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: I tak, to trzeba poprawny format printf z drugiej odpowiedzi.