2010-03-08 6 views
20

Es scheint, als ob ich Bitverschiebung in C/C++ um mehr als 32 Bits durchführen könnte, vorausgesetzt, der linke Operand der Schicht ist lang. Aber das scheint zumindest beim g ++ Compiler nicht zu funktionieren.Wie verschiebe ich Bit um mehr als 32 Bit?

Beispiel:

unsigned long A = (1L << 37) 

gibt

A = 0 

, die nicht das, was ich will. Fehle ich etwas oder ist das einfach nicht möglich?

-J

+2

Long ist 32 Bits auf den meisten Architekturen .... –

+0

Verwenden 'LL' statt nur' L' –

Antwort

11

Re-versuchen dies eine Variable vom Typ mit uint64_t (von stdint.h) statt long. uint64_t ist garantiert 64 Bit lang und sollte sich wie erwartet verhalten.

+4

Wenn 'long' 32 Bit ist, dann ist' (1L << 37) 'unabhängig vom Typ der Variablen gleich Null. '1' muss ebenfalls in den Zieltyp umgewandelt werden. – Potatoswatter

+7

@Potatoswatter: Wenn "long" 32 Bit ist, ist das Verhalten ** undefiniert ** für Verschiebungen von 32 Bit oder mehr. In der Tat, auf GCC/x86, "1L << 37 == 32". Gleiches gilt für GCC/PowerPC. (Was passiert, ist der Shifter bekommt nur die niedrigen fünf Bits.) –

+1

@Dietrich: True. Mein Punkt (den ich anscheinend auch vernachlässigt habe) ist, dass der Ausdruck, den er wahrscheinlich wollte, "1LL << 37" ist. – Potatoswatter

9

Nun, es ist abhängig von der tatsächlichen Größe des Typs long (genauer gesagt, seine Breite in Bits). Am wahrscheinlichsten auf Ihrer Plattform long hat Breite von 32 Bits, so erhalten Sie 0 als Ergebnis (siehe auch P.S. unten). Verwenden Sie einen größeren Typ. long long vielleicht?

P.S. Als eine zusätzliche Anmerkung, erzeugt eine Art von mehr Bits als seine Breite (oder die gleiche Anzahl von Bits) undefinierten Verhalten in C und C++ (C++ verwendet den Begriff Länge anstelle von Breite) verschiebt. Also, Sie sind nicht 0 von bekommen garantiert weder 1L << 37 noch 1L << 32 auf einer Plattform, wo long Breite 32

+0

Richtig, das Grundprinzip, dass wäre in einigen CPUs die Rotieroperation bei den niedrigen Bits nur schauen und Der C-Compiler darf dieses Verhalten duplizieren.So (i << 37) auf einem 32-Bit-Int kann das gleiche sein wie (i << 5). Kurs "undefiniertes Verhalten" bedeutet, dass es absolut alles kann, aber das ist wahrscheinlich das andere "beobachtete" Verhalten neben der Rückkehr 0. –

+0

@Ben Voigt: Genau. Darüber hinaus ist dies eines der Beispiele von UB, die sich tatsächlich in der Praxis manifestieren. Auf einer solchen Hardware kann man oft bemerken, dass zum Beispiel "int i = 5; i << = 37; 'erzeugte unterschiedliches Ergebnis von 'int i = (5 << 37);', da ersterer von der CPU zur Laufzeit und letzterer vom Compiler zur Kompilierzeit berechnet wurde. – AnT

26

A hat gleich 0, da A nur 32 Bits hat, so natürlich Sie alle Bits verschieben sich aus nach links lassen nur noch 0 Bits übrig. Sie benötigen ein 64-Bit zu machen:

unsigned long long A = (1ULL << 37); 

Oder wenn Sie beabsichtigen ++ Visual C zu verwenden:

unsigned __int64 A = (1ULL << 37); 
+0

Ich denke, dass ich an Java gewöhnt bin, wo eine Länge von 64 Bit garantiert ist. Wenn es nur 32 Bit ist, wie unterscheidet es sich von einem Int? –

+3

Um die Dinge etwas klarer zu machen, möchte ich etwas klarstellen. Die Größen der C-Typen char, short, int, long und long long variieren je nach Rechnerarchitektur und Compiler. Der C-Standard garantiert jedoch diese Beziehung: sizeof (char) <= sizeof (kurz) <= sizeof (int) <= sizeof (lang) <= sizeof (lang lang) Aber für typische 32-Bit-Maschinen , das ist wahrscheinlich, was Sie kompilieren, die Größen für char, kurz, int, lang und lang lang sind 8, 16, 32, 32 und 64 Bits jeweils. – Cthutu

+5

Eine pedantische Bemerkung: C-Standard garantiert das nicht. C++ Standard tut es. C-Standard besagt, dass 'Bereich von char <= Bereich von kurz <= Bereich von int <= Bereich von lang <= Bereich von lang lang, aber es sagt nichts über die" Größe von ". Formal könnte die Beziehung für "sizeof" in C nicht gelten, obwohl das eine sehr seltsame und exotische Sache wäre. – AnT

2

Sind Sie sicher, dass eine lange 64 Bits mit Ihrem bestimmten Betriebssystem und Compiler? Verwenden Sie stdint.h und versuchen, es wie folgt aus:

#include <stdint.h> 

uint64_t x = (1ULL << 37); 
0

Neue C++ Standard führt LL und ULL-Suffixe für Ganzzahlliterale. Sie könnten versuchen, sie zu verwenden, da alle neuesten Compiler sie unterstützen. Aber Sie sollten wissen, dass es nicht Teil des aktuellen C++ Standards ist.

long long A = (1LL << 37) 
0

In Ihrem Fall sind Sie auf die Sprachbasistypen beschränkt. Eine generische Lösung für [Quasi] beliebige ganze Zahlen ist Integer Klasse unter Crypto++.

-1

Sie haben die Argumente umgekehrt.

unsigned long A1 = (1L << 37); // is 2 to the 37th 
unsigned long A = (37UL<<1UL); // has just multiplied 37 by 2 
+0

Warum glaubst du, dass sie 37 * 2 wollen? Es gibt keine winzige Ahnung, dass das das Ziel in der Frage war. – ShadowRanger

Verwandte Themen