2012-12-10 12 views
9

Ok, questo è un problema strano:Non firmato a lungo Fuori intervallo?

  • sto usando unsigned long long variabili (ho usato anche long quelli, con lo stesso effetto)
  • ho bisogno di essere in grado di memorizzare 64 interi bit (sizeof restituisce 8, che va bene)

Tuttavia, quando sto cercando di andare a valori come 1<<63, ed eseguire alcune semplici operazioni bit per bit, I - stranamente - sembrano essere sempre valori negativi. Perché?

mio codice di prova:

unsigned long long c = 0; 

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

uscita:

c = 72057594037927936 
c = -9151314442816847872 

Note a margine:

  1. Naturalmente, la stessa cosa accade anche se faccio direttamente c = 1l<<63.
  2. Tutti i test effettuati su Mac OS X 10.6, e compilati utilizzando Apple LLVM compilatore 3,0

Qualche suggerimento?

+1

Se * hai * numeri interi a 64 bit, potresti preferire usare uint64_t. –

+0

So che hai già selezionato una risposta, ma ho ancora una domanda: stai compilando per un core a 64 bit? Qual è 'sizeof (long)'? Sono sorpreso che '1l << 63' funzioni, come avrei pensato che avrebbe spostato un' 1l' a 32 bit di 63 bit, lasciando il valore zero. Ma se 'sizeof (long)' è anche 8, forse è per questo che funziona. Se ho ragione, allora c'è un po 'di verità nella risposta di Jesse Rusak, anche se quella risposta non risolverà il tuo problema. – phonetagger

+2

Sì, il '1l' dovrebbe essere' 1ull' per garantire che sia lungo almeno 64 bit. – AusCBloke

risposta

22

La parte d dello specificatore %lld indica allo printf che l'argomento deve essere considerato come un intero con segno. Utilizzare invece u: %llu.

Dalle pagine man:

d, i

L'argomento int viene convertito in firmato notazione decimale.

o, u, x, X

L'argomento int unsigned viene convertito senza segno ottale (o), senza segno decimale (u), o senza segno esadecimale (x e X) notazione.

+0

OK, ora è una di quelle volte, quando dopo un sacco di grattacapi e ... sforzi di debug a più livelli, mi sento un idiota ... lol. Credo di aver imparato qualcosa di veramente prezioso. (Ovviamente il problema riguardava qualcosa di molto più grande ... e non solo un test di 2 linee). Grazie mille, amico! Mi hai sicuramente risparmiato un sacco di tempo! ;-) –

+1

@ Dr.Kameleon: Nessun problema, capita a tutti. – AusCBloke

4

Penso che stai facendo qualcosa di indefinito qui.Penso che l'espressione 1l << 63 non sia definita in C, poiché il compilatore rappresenterà 1l in un tipo firmato e lo spostamento di 63 bit causa un overflow con segno (che non è definito in C). Non sono un esperto, ma sembra che tu voglia 1ull << 63.

Il codice originale, infatti, si lamenta di questo se si passa -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: E, sì, allora avete bisogno il formato printf corretto dal altra risposta.

Problemi correlati