2016-05-25 10 views
1

Hier ist das Programm, dessen Zusammenstellung Ausgang macht mich weinen:2^32 - 1 nicht Teil von uint32_t?

#include <inttypes.h> 

int main() 
{ 
     uint32_t limit = (1 << 32) - 1; // 2^32 - 1 right? 
} 

und hier ist die Zusammenstellung Ausgang:

~/workspace/CCode$ gcc uint32.c 
uint32.c: In function ‘main’: 
uint32.c:5:29: warning: left shift count >= width of type [-Wshift-count-overflow] 
     uint32_t limit = (1 << 32) - 1; // 2^32 - 1 right? 

Ich dachte, dass (1 << 32) - 1-2^32 gleich - 1, und dass ganze Zahlen ohne Vorzeichen auf 32 Bits reichen von 0 bis 2^32 - 1, ist das nicht der Fall? Was habe ich falsch gemacht?

+0

Die Warnung sagt alles. Sie können den Wert eines Ausdrucks, der nicht ausgedrückt werden kann, nicht berechnen. –

+0

Vielleicht ist das Problem hier, dass (1 << 32) erfordert 1 Bit mehr Speicherplatz (33 Bits), um den Wert zu speichern - so der Compiler passt, da Sie mit einer 32-Bit-Variable arbeiten. –

+1

mit 32-Bit int, 2^32 - 1 passt (unsigned) ... Problem ist, 2^32 wird nicht, und es ist ein Teil des Ausdrucks, den Sie berechnen 2^32-1 mit. Aus anderen Gründen werden Sie wahrscheinlich am Ende trotzdem die richtige Antwort erhalten, da uint32_t modulo 2^32 ist. – Dmitri

Antwort

4

Sie haben zwei Fehler:

  • 1 vom Typ int, so dass Sie Berechnen des Anfangswerts als int, nicht als uint32_t.
  • Wie die Warnung besagt, muss das Verschiebungsargument von Schichtoperatoren kleiner als die Breite des Typs sein. 1 << 32 ist undefiniertes Verhalten wenn int 32 Bits oder weniger ist. (uint32_t)1 << 32 wäre auch undefiniert.

(auch zu beachten, dass 1 << 31 würde Verhalten als auch undefiniert sein, wenn int 32 Bits sind, wegen des Überlaufes)

Da Arithmetik 2^32 sowieso Modulo gemacht wird, ein einfacher Weg, dies zu tun, ist nur

uint32_t x = -1; 
uint32_t y = (uint32_t)0 - 1; // this way avoids compiler warnings 
+0

Das sieht für mich wie C++ aus! –

+0

@Ian: Fein. : P. – Hurkyl

+0

ist die 1 in -1 Art von Uint32_t konvertiert? Wie kommt es, dass es gut funktioniert? – Simonlbc

4

Die Warnung ist korrekt, das höchste Bit in einer 32-Bit-Nummer ist das 31. Bit (0 indiziert), also die größte Verschiebung vor dem Überlauf ist 1 << 30 (30 wegen des Vorzeichen-Bits). Auch wenn Sie -1 irgendwann tun, muss das Ergebnis von 1 << 32 gespeichert werden und es wird in einem int gespeichert (was in diesem Fall geschieht, 32 Bits zu sein). Daher erhalten Sie die Warnung.

Wenn Sie wirklich das max des 32 bit unsigned int erhalten müssen Sie es die nette Art und Weise tun sollten:

#include <stdint.h> 

uint32_t limit = UINT32_MAX; 
+1

'1 << 31 'ist auch undefiniertes Verhalten (Verschiebung in das Vorzeichen-Bit) –

+1

... es sei denn,' int' ist breiter als 32 Bit. – AnT

1

Der Compiler verwendet intern intern in Ihrem Beispiel, wenn versucht wird, die Zielkonstante zu berechnen. Stellen Sie sich vor, dass der Compiler keine Optimierung zur Verfügung hatte und Assembler für Ihre Schicht generieren sollte. Die Zahl 32 wäre zu groß für den 32-Bit-Int-Shift-Befehl.

Wenn Sie alle Bits setzen möchten, verwenden Sie ~ 0

+0

'~ 0u' ist eher für Bit-Fiddling geeignet, vor allem wenn man bedenkt, dass das OP ein vorzeichenloses Ergebnis haben möchte. – AnT

+0

Genauer gesagt, OP möchte ein 'uint32_t'-Ergebnis mit dem maximalen Wert, so dass selbst' ~ 0u' falsch ist, wenn der 'unsigned int' des Compilers weniger als 32 Bits breit ist. –

Verwandte Themen