Ich versuche, eine Art Linksverschiebung zu machen, die am Anfang Nullen anstelle von Einsen hinzufügen würde. Zum Beispiel, wenn ich shift 0xff
verließ, bekomme ich das:
Wenn ich es jedoch richtig verschiebe, bekomme ich das:
%Vor%Gibt es irgendeine Operation, die ich verwenden könnte, um das Äquivalent einer Linksverschiebung zu erhalten? Das würde ich gerne bekommen:
%Vor%Irgendwelche Vorschläge?
Bearbeiten
Um die Kommentare zu beantworten, hier ist der Code, den ich verwende:
%Vor%Ausgabe:
%Vor%Da es im Allgemeinen scheint, dass es funktionieren sollte, interessiert mich, warum dieser spezifische Code nicht funktioniert. Irgendeine Idee?
So funktionieren C und Binärarithmetik:
Wenn Sie shift 0xff << 3
verlassen haben, erhalten Sie binary: 00000000 11111111 << 3 = 00000111 11111000
Wenn Sie 0xff >> 3
nach rechts verschieben, erhalten Sie binary: 00000000 11111111 >> 3 = 00000000 00011111
0xff
ist ein (vorzeichenbehafteter) int mit dem positiven Wert 255
. Da es positiv ist, ist das Ergebnis der Verschiebung ein wohldefiniertes Verhalten in C und C ++. Es wird keine arithmetischen Verschiebungen, keine Art oder schlecht definiertes Verhalten machen.
Ausgabe:
%Vor%Sie machen also etwas Seltsames in Ihrem Programm, weil es nicht wie erwartet funktioniert. Vielleicht verwenden Sie Zeichenvariablen oder C ++ - Zeichenliterale.
Quelle: ISO 9899: 2011 6.5.7.
BEARBEITEN nach der Aktualisierung der Frage
int number = ~0;
gibt Ihnen eine negative Zahl, die -1 entspricht, unter Annahme von Zweierkomplement.
number = number << 4;
ruft undefiniertes Verhalten auf, da Sie eine negative Zahl verschoben haben. Das Programm implementiert undefiniertes Verhalten korrekt, da es entweder etwas oder gar nichts tut. Es kann fffffff0 drucken, oder es kann einen rosa Elefanten drucken, oder es kann die Festplatte formatieren.
number = number >> 4;
ruft implementierungsdefiniertes Verhalten auf. In Ihrem Fall behält der Compiler das Vorzeichenbit bei. Dies wird als arithmetische Verschiebung bezeichnet, und die arithmetische Rechtsverschiebung funktioniert so, dass das MSB mit einem beliebigen Bitwert gefüllt wird hatte vor der Schicht. Wenn Sie also eine negative Zahl haben, werden Sie feststellen, dass das Programm "in Eins" wechselt.
In 99% aller realen Fälle macht es keinen Sinn, bitweise Operatoren für vorzeichenbehaftete Zahlen zu verwenden. Stellen Sie daher immer sicher, dass Sie vorzeichenlose Zahlen verwenden und dass keine der gefährlichen impliziten Konvertierungsregeln in C / C ++ sie in vorzeichenbehaftete Zahlen umwandelt (weitere Informationen zu gefährlichen Konvertierungen finden Sie unter "Die Regeln für die ganzzahlige Promotion" und "die üblichen arithmetischen Konvertierungen") ", viele gute Informationen über diejenigen auf SO).
EDIT 2 , einige Informationen aus dem Grundlagendokument V5.10 des C99-Standards:
6.5.7 Bitweises Shift-Operatoren
Die Beschreibung der Schichtoperatoren in K & amp; R legt nahe, dass eine Verschiebung um a long count sollte dazu führen, dass der linke Operand zu lange vorher erweitert wird verschoben werden. Eine intuitivere Praxis, die vom C89 unterstützt wird Komitee, ist, dass die Art der Verschiebung Anzahl hat keinen Einfluss auf die Art des Ergebnisses.
Ruhige Änderung in C89
Das Verschieben um eine lange Anzahl führt nicht mehr dazu, dass der verschobene Operand zu lange. Der C 89-Ausschuss bekräftigte die eingeräumte Ausführungsfreiheit indem K & amp; R die signierte Rechtsverschiebungsoperation nicht zum Signieren benötigt verlängern, da eine solche Anforderung den schnellen Code verlangsamen könnte Die Nützlichkeit von Vorzeichenverlängernden Verschiebungen ist marginal. (Verschiebung a negatives Zweierkomplement ganzzahlig arithmetisch richtig ein Platz ist nicht das gleiche wie das Teilen durch zwei!)
Wenn Sie 0xff explizit verschieben, funktioniert es wie erwartet
%Vor% Dies sollte nur möglich sein, wenn 0xff
vom Typ der signierten Breite 8 ist ( char
und signed char
auf populären Plattformen).
Also, im allgemeinen Fall:
Sie müssen unsignierte Ints verwenden
(unsigned type)0xff
Rechtsverschiebung funktioniert als Division mit 2 (mit Abrundung, wenn ich richtig verstehe).
Wenn Sie also 1 als erstes Bit haben, haben Sie einen negativen Wert und nach der Division ist es wieder negativ .
Die beiden Arten der Rechtsverschiebung, von denen Sie sprechen, heißen Logical Shift und Arithmetische Verschiebung . C und C ++ verwenden die logische Verschiebung für vorzeichenlose Integer, und die meisten Compiler verwenden die arithmetische Verschiebung für eine ganze Zahl mit Vorzeichen, aber dies ist nicht durch den Standard garantiert, was bedeutet, dass der Wert von right, der ein negatives vorzeichenbehaftetes int umschaltet, implementiert wird.
Da Sie eine logische Verschiebung wünschen, müssen Sie zur Verwendung einer Ganzzahl ohne Vorzeichen wechseln. Sie können dies tun, indem Sie Ihre Konstante durch 0xffU
ersetzen.
Um Ihren wirklichen Code zu erklären, brauchen Sie nur die C ++ - Versionen der Zitate aus dem C-Standard, die Lundin in Kommentaren gab:
%Vor%Undefiniertes Verhalten. [expr.shift] sagt
%Vor%Der Wert von E1 & lt; & lt; E2 ist E1 nach links verschobene E2-Bitpositionen; geräumt Bits sind Null gefüllt. Wenn E1 einen vorzeichenlosen Typ hat, wird der Wert von Ergebnis ist E1 × 2
, Modulo um eins mehr als der Maximalwert reduziert darstellbar im Ergebnistyp. Andernfalls, wenn E1 einen signierten Typ hat und nicht negativer Wert , und E1 × 2 ist im Ergebnis darstellbar Typ, dann ist das der resultierende Wert; Ansonsten ist das Verhalten undefiniert .
Implementierungsdefiniertes Ergebnis, in diesem Fall hat Ihre Implementierung eine arithmetische Verschiebung ergeben:
Der Wert von E1 & gt; & gt; E2 ist E1 nach rechts verschobene E2-Bitpositionen. Wenn E1 hat ein vorzeichenloser Typ oder wenn E1 einen Typ mit Vorzeichen und einen nicht negativen Wert hat, der Wert des Ergebnisses ist der Integralanteil des Quotienten von E1 / 2
. Wenn E1 einen Typ mit Vorzeichen und einen negativen Wert hat, wird das Ergebnis angezeigt Wert ist implementierungsdefiniert
Sie sollten einen unsignierten Typ verwenden:
%Vor%Ausgabe:
%Vor%Um meine 5 Cent hier hinzuzuverdienen ... Ich stehe genau dem gleichen Problem gegenüber. Ich habe einige oberflächliche Nachforschungen darüber angestellt und das sind meine Ergebnisse:
%Vor%Es würde erscheinen (in Ermangelung jemandes mit detaillierten Kenntnissen), dass der C-Compiler in XCode für Mac OS X v5.0.1 das MSB als ein Übertragsbit reserviert, das mit jeder Schicht mitgezogen wird.
Etwas ärgerlich, das Gegenteil ist NICHT wahr: -
%Vor%Ich stimme völlig mit den Leuten darüber überein, dass das Vorzeichen des Operanden keine Auswirkung auf das Verhalten des Schichtoperators hat.
Kann jemand die Spezifikation für die Posix4-Implementierung von C näher beleuchten? Ich glaube, dass eine endgültige Antwort dort ruhen kann.
In der Zwischenzeit scheint es, dass die einzige Problemumgehung ein Konstrukt in den folgenden Zeilen ist: -
%Vor%Das funktioniert - ärgerlich, aber notwendig.
Tags und Links c c++ bit-manipulation bit-shift