2009-06-21 1 views
8

ich eine dritte Partei Quellcode Scannen Findbugs mit (nur vorsichtig zu sein, in sie, bevor die Integration von mir), und fanden die folgende Warnung:Findbugs Warnung: Ganzzahlverschiebung um 32 - was bedeutet das?

long a = b << 32 | c 

Bug: Integer Verschiebung um 32 Muster-ID: ICAST_BAD_SHIFT_AMOUNT Typ: BSHIFT, Kategorie: KORREKTHEIT

der Code führt eine ganzzahlige Verschiebung um eine konstante Menge außerhalb des Bereichs 0..31. Dies hat zur Folge, dass die unteren 5 Bits des ganzzahligen Werts verwendet werden, um zu entscheiden, um wie viel verschoben werden soll. Diese wahrscheinlich ist nicht erwartet wurde, und es zumindest verwirrend.

Könnte jemand bitte erklären, was genau das oben genannte bedeutet?

Danke! (Ich bin ein ziemlich Neuling in Java-Programmierung)

Antwort

30

Vom Java Language Specification:

Falls der begünstigt Typ des linken Operanden int ist, nur die fünf niederwertigsten Bits des rechten Operanden werden als die Verschiebungsstrecke verwendet. Es ist, als ob der rechte Operand einem bitweisen logischen UND-Operator & (§15.22.1) mit dem Maskenwert 0x1f unterzogen würde. Die tatsächlich genutzte Verschiebestrecke liegt daher immer im Bereich von 0 bis einschließlich 31.

Also, wenn b ein int ist, ist der Ausdruck identisch mit

long a = b | c; 

die ich sehr Zweifel ist, was beabsichtigt ist. Es sollte wohl

gewesen
long a = ((long) b << 32) | c; 

(Wenn b bereits eine lang ist, ist der Code korrekt und FindBugs irrt über den Bug).

+0

So,' int >> 32 (0x100000) == int >> 0 (0x00000) '? –

+1

Seltsame Pseudo-Syntax, die Sie verwenden, aber ja, das ist es. – UndefinedBehavior

5

Edited: Das Problem mit ziemlicher Sicherheit kommt von der Tatsache, dass ‚b‘ ist ein ‚int‘ und keine ‚long‘.

In C, wenn 'b' ist eine Ganzzahl anstelle einer langen und Sie verschieben um 32 Bits, alle Bits aus dem ursprünglichen Wert wurden entfernt, so dass das Ergebnis des Gesamtausdrucks wäre der gleiche wie 'c' Sie würden undefiniertes Verhalten aufrufen, so dass jedes Ergebnis zulässig ist. Java definiert Dinge anders - wie in dem Kommentar von Rasmus Faber und der gewählten Antwort angemerkt - und verschiebt überlange Verschiebungen modulo die maximale Anzahl von Bits, die verschoben werden können. [Es scheint eine seltsame Art, Geschäfte zu machen; Ich hätte wahrscheinlich eine Ausnahme in einer Sprache arrangiert, die sie hat. Es ist jedoch klar definiert, was wichtiger ist als genau, was die Definition ist.] Die Nötigung auf 64 Bits tritt nicht auf, während der Ausdruck ausgewertet wird; Es tritt auf, wenn der Ausdruck vollständig ist und die Zuweisung erfolgt.

Der Verweis auf 5 Bits ist ... faszinierend. Das bedeutet, dass Sie, wenn Sie um beispielsweise 48 oder 110000 nach links gehen, dasselbe tun, als würden Sie um 16 nach links verschieben. Alternativ ist "x << n" dasselbe wie "x << (n % 32)".

+1

D'oh, du hast Recht, löschte meine Antwort und upmoded dir :) –

+1

Der erste Teil Ihrer Antwort ist falsch. In Jave ist b << 32 b, nicht Null. Das zweite Paragraah ist jedoch korrekt. –

+1

Korrektur: In C ist das Verhalten _undefined_, wenn ein Wert mit einem Argument außerhalb des Bereichs [0, typewidth - 1] verschoben wird. Zum Beispiel geben die opencl Compiler von nvidia und intel mir ein anderes Verhalten für den Ausdruck 'b >> 32'. – notso