Ich habe die folgende Codezeile gesehen hier in C.
int mask = ~0;
Ich habe den Wert von gedruckt mask in C und C++. Es druckt immer -1.
Da habe ich einige Fragen:
Warum Werte zuweisen ~0 zum Maske Variable?
Was ist der Zweck von ~0?
Können wir verwenden -1 Anstatt von ~0?
~0 ist nur gleich -1 im Zweierkomplement
– phuklv
23. September 2017 um 6:21 Uhr
@PaulFloyd: Die verlinkte Quelle handelt von einer reinen Übung zum Fummeln … so nützlich wie das Heben von Gewichten
– 6502
23. September 2017 um 6:33 Uhr
Verwandte: Ist es sicher, -1 zu verwenden, um alle Bits auf wahr zu setzen?
– Cody Grey ♦
23. September 2017 um 10:41 Uhr
Die Verwendung von signiertem Typ für eine Maske sagt mir, dass in Ihrem Code schreckliche Dinge passieren.
– Sopel
23. September 2017 um 12:58 Uhr
Mögliches Duplikat von Was macht der Operator ~?
– Bernhard Barker
23. September 2017 um 19:04 Uhr
Es ist eine portable Möglichkeit, alle binären Bits in einer Ganzzahl auf 1 Bit zu setzen, ohne wissen zu müssen, wie viele Bits in der Ganzzahl in der aktuellen Architektur enthalten sind.
-1 setzt auch alle Bits in einer Ganzzahl auf 1, ohne die Breite von zu kennen int Typ. Es impliziert nur die Verwendung des Zweierkomplements
– phuklv
23. September 2017 um 6:24 Uhr
@LưuVĩnhPhúc richtig. Die Methode ~0 hat weniger Abhängigkeiten. Funktioniert auf unsignierten Nicht-Zwei-Komplement-Systemen und ist (wohl) weniger kryptisch.
– Richard Hodges
23. September 2017 um 7:02 Uhr
@chqrlie warum nicht? Übrigens ist die Verwendung von vorzeichenbehafteten Werten für die Bitmasken eine seltsame Idee.
– 0___________
23. September 2017 um 8:01 Uhr
@ PeterJ_01: Wenn long hat mehr Bits als intdann ~0u (der Typ hat unsigned) wäre Null-erweitert als Teil der Initialisierung u.
– hmakholm hat Monica übrig gelassen
23. September 2017 um 12:45 Uhr
Dies ist nicht portierbar, wenn es sich um das eigene Komplement handelt: Es ergibt eine negative Null, die ein konformer Compiler als Trap-Darstellung entscheiden kann. An diesem Punkt haben Sie UB. Fairerweise kann gesagt werden, dass eine solche Implementierung nicht möglich ist haben ein All-Eins-Wert für int an erster Stelle.
– Kevin
23. September 2017 um 20:46 Uhr
phuclv
C und C++ erlauben 3 verschiedene vorzeichenbehaftete Integer-Formate: Vorzeichengröße, Einerkomplement und Zweierkomplement
~0 wird All-One-Bits erzeugen unabhängig vom Zeichenformat das System verwendet. So ist es tragbarer als -1
Sie können die hinzufügen U Suffix (dh -1U), um ein Nur-Eins-Bitmuster zu erzeugen tragbar1. Jedoch ~0zeigt die Absicht klarer an: Invertieren Sie alle Bits im Wert 0, während -1 anzeigt, dass ein Wert von minus eins benötigt wird, nicht seine binäre Darstellung
1 denn vorzeichenlose Operationen sind immer reduziert modulo die Zahl, die um eins größer ist als der größte Wert, der durch den resultierenden Typ dargestellt werden kann
Der Text besagt, dass eine 32-Bit-Ganzzahl im Zweierkomplement angenommen werden kann
– 6502
23. September 2017 um 6:27 Uhr
Beachten Sie das für alle unsignierte Typen, u = -1; setzt alle Bits auf 1. Für vorzeichenlose Typen breiter als unsigned, u = ~0; und u = -1u; unterlassen Sie.
– chux – Wiedereinsetzung von Monica
15. September 2018 um 14:31 Uhr
Das auf einer 2er-Komplement-Plattform (das wird angenommen) gibt Ihnen -1, aber das direkte Schreiben von -1 ist durch die Regeln verboten (nur Ganzzahlen 0..255, unär !, ~ und binär &, ^, |, +, << und >> sind erlaubt).
Sie studieren eine Codierungsaufgabe mit einer Reihe von Einschränkungen für Operatoren und Sprachkonstruktionen, um bestimmte Aufgaben auszuführen.
Das erste Problem ist gibt den Wert -1 zurück ohne den Einsatz von - Operator.
Auf Maschinen, die negative Zahlen mit Zweierkomplement darstellen, der Wert -1 wird mit allen auf gesetzten Bits dargestellt 1Also ~0 wertet zu -1:
/*
* minusOne - return a value of -1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 2
* Rating: 1
*/
int minusOne(void) {
// ~0 = 111...111 = -1
return ~0;
}
Andere Probleme in der Datei werden nicht immer korrekt implementiert. Das zweite Problem, das Zurückgeben eines booleschen Werts, der die Tatsache darstellt, dass an int Wert würde in ein 16-Bit-Zeichen passen short hat einen fehler:
/*
* fitsShort - return 1 if x can be represented as a
* 16-bit, two's complement integer.
* Examples: fitsShort(33000) = 0, fitsShort(-32768) = 1
* Legal ops: ! ~ & ^ | + << >>
* Max ops: 8
* Rating: 1
*/
int fitsShort(int x) {
/*
* after left shift 16 and right shift 16, the left 16 of x is 00000..00 or 111...1111
* so after shift, if x remains the same, then it means that x can be represent as 16-bit
*/
return !(((x << 16) >> 16) ^ x);
}
Linksverschiebung eines negativen Werts oder einer Zahl, deren verschobener Wert außerhalb des Bereichs von liegt int hat ein undefiniertes Verhalten, Rechtsverschiebung ein negativer Wert ist implementierungsdefiniert, daher ist die obige Lösung falsch (obwohl es wahrscheinlich die erwartete Lösung ist).
Vor laaaanger Zeit sparte man auf diese Weise Speicherplatz bei extrem begrenzten Geräten wie dem 1K ZX 80 oder ZX 81 Computer. In BASIC würden Sie
Let X = NOT PI
statt
LET X = 0
Da Zahlen als 4-Byte-Gleitkommazahlen gespeichert wurden, benötigt letztere 2 Bytes mehr als die erste NOT-PI-Alternative, bei der NOT und PI jeweils ein einzelnes Byte beanspruchen.
Nicht genau. In diesen Beispielen wurden alle (Schlüssel-)Wörter durch einzelne Bytes codiert, ebenso das Gleichheitszeichen, Variablennamen und die sichtbar Null selbst. Auf die numerischen Konstanten folgte jedoch (ein Escape-Byte?) plus ein 4-Byte-Gleitkommawert, der vom Executor verwendet, aber nicht in der Quelle angezeigt wurde. Daher beträgt der Größenunterschied hier 3 oder sogar 4 Bytes, nicht 2.
– CiaPan
24. September 2017 um 15:12 Uhr
Ich sollte arbeiten … habe das gerade auf einem ZX Spectrum-Emulator gemacht und auf Band / Festplatte gespeichert. Der erste verwendet 40 und der zweite 35 Bytes, also eine Differenz von 5 Bytes. Nun, wenn Sie nur 1k wie beim ZX 81 haben, schätze ich, dass das ein halbes Prozent an Dateigröße einspart und weshalb es verwendet wurde … Zurück zur OP-Frage – würden Sie in der Lage sein, ein oder zwei Bytes zu sparen (oder 5) heute, indem Sie beispielsweise x = ~0 anstelle von x = -1 verwenden? Vielleicht mit einer Konvertierung wie long x = ~0 ?
– skak
4. Oktober 2017 um 12:24 Uhr
Ich sollte wirklich arbeiten … habe dies gerade in c auf ein paar einfache Arten versucht, aber die kompilierte Datei hatte die gleiche Größe für -1, ~ 0 und ~ (0x00) … Ich bin mir sicher, dass es einige Architekturen gibt, bei denen dies der Fall ist ein Byte oder so sparen, aber solche Kuriositäten müssen heutzutage natürlich um jeden Preis vermieden werden. Die kompilierten Dateien waren ungefähr 8,5 kByte groß. Das würde dem armen ZX81 einen Herzinfarkt bescheren …
– skak
4. Oktober 2017 um 12:41 Uhr
Moderne C-Compiler sind intelligent genug, um das zu erkennen ~0 und -1 als gleichen Wert. Sie können den Code auch entweder auf maximale Geschwindigkeit oder auf minimale Größe optimieren, sodass Sie mit Kompilierungsoptionen spielen müssten. Darüber hinaus kann der kompilierte Code auf 4, 8 oder 16 Bytes aufgerundet werden, um die Einstiegspunkte von Funktionen besser auszurichten, also betrachten obj Dateigröße ist für Ihre Zwecke ungeeignet. Vielleicht kompilieren Sie lieber den C-Code zum Assemblieren oder disassemblieren sogar das kompilierte Objektmodul (mit einem Tool wie objdump), um die Byte-für-Byte-Darstellung Ihres Codes zu sehen.
– CiaPan
9. Oktober 2017 um 7:32 Uhr
Gibt es auf diesen Systemen keinen Integer-Typ? Und wie kann PI in einem Byte gespeichert werden?
– phuklv
30. Juni 2018 um 12:36 Uhr
Es gibt mehrere Möglichkeiten, Zahlen über alle Computerarchitekturen hinweg zu codieren. Bei Verwendung des Zweierkomplements gilt dies immer:~0 == -1. Andererseits verwenden einige Computer das 1er-Komplement zum Codieren negativer Zahlen, für die das obige Beispiel nicht wahr ist, weil ~0 == -0. Yup, 1s Komplement hat negative Null, und deshalb ist es nicht sehr intuitiv.
Also zu deinen Fragen
Die ~ 0 wird der Maske zugewiesen, sodass alle Bits in der Maske gleich 1 sind -> machen mask & sth == sth
Die ~0 wird verwendet, um alle Bits unabhängig von der verwendeten Plattform gleich 1 zu machen
Sie können -1 anstelle von ~0 verwenden, wenn Sie sicher sind, dass Ihre Computerplattform die 2er-Komplement-Zahlencodierung verwendet
Mein persönlicher Gedanke – machen Sie Ihren Code so plattformunabhängig wie möglich. Die Kosten sind relativ gering und der Code wird ausfallsicher
Nicht genau. In diesen Beispielen wurden alle (Schlüssel-)Wörter durch einzelne Bytes codiert, ebenso das Gleichheitszeichen, Variablennamen und die sichtbar Null selbst. Auf die numerischen Konstanten folgte jedoch (ein Escape-Byte?) plus ein 4-Byte-Gleitkommawert, der vom Executor verwendet, aber nicht in der Quelle angezeigt wurde. Daher beträgt der Größenunterschied hier 3 oder sogar 4 Bytes, nicht 2.
– CiaPan
24. September 2017 um 15:12 Uhr
Ich sollte arbeiten … habe das gerade auf einem ZX Spectrum-Emulator gemacht und auf Band / Festplatte gespeichert. Der erste verwendet 40 und der zweite 35 Bytes, also eine Differenz von 5 Bytes. Nun, wenn Sie nur 1k wie beim ZX 81 haben, schätze ich, dass das ein halbes Prozent an Dateigröße einspart und weshalb es verwendet wurde … Zurück zur OP-Frage – würden Sie in der Lage sein, ein oder zwei Bytes zu sparen (oder 5) heute, indem Sie beispielsweise x = ~0 anstelle von x = -1 verwenden? Vielleicht mit einer Konvertierung wie long x = ~0 ?
– skak
4. Oktober 2017 um 12:24 Uhr
Ich sollte wirklich arbeiten … habe dies gerade in c auf ein paar einfache Arten versucht, aber die kompilierte Datei hatte die gleiche Größe für -1, ~ 0 und ~ (0x00) … Ich bin mir sicher, dass es einige Architekturen gibt, bei denen dies der Fall ist ein Byte oder so sparen, aber solche Kuriositäten müssen heutzutage natürlich um jeden Preis vermieden werden. Die kompilierten Dateien waren ungefähr 8,5 kByte groß. Das würde dem armen ZX81 einen Herzinfarkt bescheren …
– skak
4. Oktober 2017 um 12:41 Uhr
Moderne C-Compiler sind intelligent genug, um das zu erkennen ~0 und -1 als gleichen Wert. Sie können den Code auch entweder auf maximale Geschwindigkeit oder auf minimale Größe optimieren, sodass Sie mit Kompilierungsoptionen spielen müssten. Darüber hinaus kann der kompilierte Code auf 4, 8 oder 16 Bytes aufgerundet werden, um die Einstiegspunkte von Funktionen besser auszurichten, also betrachten obj Dateigröße ist für Ihre Zwecke ungeeignet. Vielleicht kompilieren Sie lieber den C-Code zum Assemblieren oder disassemblieren sogar das kompilierte Objektmodul (mit einem Tool wie objdump), um die Byte-für-Byte-Darstellung Ihres Codes zu sehen.
– CiaPan
9. Oktober 2017 um 7:32 Uhr
Gibt es auf diesen Systemen keinen Integer-Typ? Und wie kann PI in einem Byte gespeichert werden?
– phuklv
30. Juni 2018 um 12:36 Uhr
14043400cookie-checkWas ist der Zweck von “int mask = ~0;”?yes
~0
ist nur gleich-1
im Zweierkomplement– phuklv
23. September 2017 um 6:21 Uhr
@PaulFloyd: Die verlinkte Quelle handelt von einer reinen Übung zum Fummeln … so nützlich wie das Heben von Gewichten
– 6502
23. September 2017 um 6:33 Uhr
Verwandte: Ist es sicher, -1 zu verwenden, um alle Bits auf wahr zu setzen?
– Cody Grey
♦
23. September 2017 um 10:41 Uhr
Die Verwendung von signiertem Typ für eine Maske sagt mir, dass in Ihrem Code schreckliche Dinge passieren.
– Sopel
23. September 2017 um 12:58 Uhr
Mögliches Duplikat von Was macht der Operator ~?
– Bernhard Barker
23. September 2017 um 19:04 Uhr