Was bedeutet (x ^ 0x1)! = 0?

183

Ich bin auf das folgende Code-Snippet gestoßen

if( 0 != ( x ^ 0x1 ) )
     encode( x, m );

Was heißt x ^ 0x1das Ist das eine Standardtechnik?

KodeWarrior
quelle
97
Die Verschleierung von Codes ist Standard.
raina77ow
47
Dies kann mit dem gleichen Ansatz wie eine "normale" Gleichung gelöst werden: 0 != (x ^ 1)→ xoder beide Seiten um 1 → (0 ^ 1) != (x ^ 1 ^ 1)→ vereinfachen →1 != x
Score_Under
4
Ich sehe nicht, wie if (1 != x)schwer es ist zu schreiben.
Adriano Varoli Piazza
12
Verschiedene Kommentare, zuerst von @Spook, weisen deutlich darauf hin, dass das typeof xnicht angegeben ist - daher wissen wir nicht, dass dies eine Ganzzahl in diesem C ++ - Tag-Problem ist. Sicher, wenn dies C oder xeine ganze Zahl ist, ist die Antwort einfach, aber das ist nicht gegeben und die Möglichkeit einer Überladung operator ^besteht.
chux
11
Ich sehe nicht, wie das so viele positive
Stimmen

Antworten:

277

Die XOR-Operation ( x ^ 0x1) invertiert Bit 0. Der Ausdruck bedeutet also effektiv: Wenn Bit 0 von x 0 ist oder ein anderes Bit von x 1 ist, ist der Ausdruck wahr.

Umgekehrt ist der Ausdruck falsch, wenn x == 1 ist.

Der Test ist also der gleiche wie:

if (x != 1)

und ist daher (wohl) unnötig verschleiert.

Paul R.
quelle
39
Hey, du kennst den Kontext nicht. Wenn x eine Art Bit-Flag ist, ist es IMO tatsächlich klarer, es so zu schreiben, wie es jetzt ist, als den Operator! = Zu verwenden.
Spook
40
@Spook: Es wird jedoch nicht nur ein einzelnes Bit-Flag getestet, sondern die gesamte Breite von x. Wenn Sie nur ein einzelnes Bit testen möchten, gibt es klarere Redewendungen, z. B. die Verwendung eines bitweisen UND.
Paul R
115
Unnötig verschleiert? Wissen Sie nicht, dass es unsere Aufgabe ist, Code zu verschleiern? Wenn wir einfachen Code schreiben würden, den jeder verstehen könnte, warum, wohin würde die religiöse Heiligkeit unserer Positionen in der Welt gehen? Wir wären plötzlich gewöhnliche Arbeiter wie alle anderen. Eine Verschleierung ist von Natur aus notwendig.
Thom
31
Eigentlich hat Spook recht. Der Test (x! = 1) ist nicht äquivalent. Der Code kann C ++ sein (und in C ++ kann ^ ein Operator sein, der alles tut). Sie kennen den Kontext also nicht, @Spook ist richtig.
xryl669
82
@TheThom уєт уσυ ωяιтє ιи ¢ ℓєαя тєχт
Bobobobo
78
  • ^ist die bitweise XOR- Operation
  • 0x1ist 1in hexadezimaler Schreibweise
  • x ^ 0x1wird das letzte Bit von invertieren x(siehe die XOR-Wahrheitstabelle im obigen Link, wenn Ihnen das nicht klar ist).

Also der Zustand (0 != ( x ^ 0x1 )) ist also wahr, wenn sie xgrößer als 1 ist oder wenn das letzte Bit von x0 ist. Dadurch bleibt nur x == 1 als Wert übrig, bei dem die Bedingung falsch ist. Es ist also gleichbedeutend mit

if (x != 1)

PS Eine verdammt gute Möglichkeit, eine so einfache Bedingung zu implementieren, könnte ich hinzufügen. Tu das nicht. Und wenn Sie komplizierten Code schreiben müssen, hinterlassen Sie einen Kommentar . Ich bitte dich.

Violette Giraffe
quelle
7
Es ist nicht x==0; 4 ^ 0x1ist wahr, aber 4==0offensichtlich falsch.
Fred Foo
4
"Bedingung scheint gleich zu sein if (x == 0)", ist es nicht gleich x != 1?
Andrew-Dufresne
6
Die Äquivalenz setzt voraus, dass xes sich um einen integralen Typ handelt. Wenn es ein floatoder ist double, dann glaube ich, dass der Ausdruck wahr sein würde 1.0 <= x < 2.0. Und wenn xes sich um einen benutzerdefinierten Typ handelt, könnte der Ausdruck true zurückgeben, wenn xes sich um einen Yugo, ein Känguru, einen Geburtstag eines berühmten Komponisten oder eine beliebige Zahl handelt, die mindestens drei Ziffern mit dem aktuellen Dollar-Preis für Tee in China teilt.
Supercat
4
@supercat Es gibt kein operator^für float/ double.
flauschig
1
@supercat: Wenn eine Konvertierung von Gleitkomma in Ganzzahl erforderlich ist, ist die Konvertierung implizit (erfordert keine Cast-Syntax). Bitweise Operatoren lösen jedoch keine Konvertierung aus. Sie schlagen einfach für Gleitkommatypen fehl.
Ben Voigt
49

Dies mag als vereinfachte Erklärung erscheinen, aber wenn jemand es langsam durchgehen möchte, ist es unten:

^ist ein bitweiser XOR- Operator in c, c ++ und c #.

Ein bitweises XOR nimmt zwei Bitmuster gleicher Länge und führt die logische exklusive ODER-Operation für jedes Paar entsprechender Bits aus.

Exklusives ODER ist eine logische Operation, die true ausgibt, wenn sich beide Eingänge unterscheiden (einer ist wahr, der andere ist falsch).

Die Wahrheitstabelle von a xor b :

a           b        a xor b
----------------------------
1           1           0
1           0           1
0           1           1
0           0           0

Lassen Sie uns den 0 == ( x ^ 0x1 )Ausdruck auf Binärebene veranschaulichen :

             what? xxxxxxxx (8 bits)
               xor 00000001 (hex 0x1 or 0x01, decimal 1)    
             gives 00000000
---------------------------
the only answer is 00000001

so:

   0 == ( x ^ 0x1 )    =>    x == 1
   0 != ( x ^ 0x1 )    =>    x != 1
jwaliszko
quelle
34

Es ist exklusiver OR (XOR) -Operator. Um zu verstehen, wie es funktioniert, können Sie diesen einfachen Code ausführen

    std::cout << "0x0 ^ 0x0 = " << ( 0x0 ^ 0x0 ) << std::endl;
    std::cout << "0x0 ^ 0x1 = " << ( 0x0 ^ 0x1 ) << std::endl;
    std::cout << "0x1 ^ 0x0 = " << ( 0x1 ^ 0x0 ) << std::endl;
    std::cout << "0x1 ^ 0x1 = " << ( 0x1 ^ 0x1 ) << std::endl;

Die Ausgabe wird sein

0x0 ^ 0x0 = 0
0x0 ^ 0x1 = 1
0x1 ^ 0x0 = 1
0x1 ^ 0x1 = 0

Also dieser Ausdruck

0 != ( x ^ 0x1 )

wird nur dann gleich wahr sein, wenn x! = 0x1.

Es ändert x selbst nicht. Es wird nur geprüft, ob x gleich 0 oder 1 ist. Dieser Ausdruck kann in geändert werden

if ( x != 0x1 )
Vlad aus Moskau
quelle
19

Es überprüft, ob xtatsächlich nicht 0x1... xoring xmit 0x1nur 0 führen, wenn xist 0x1... das ist ein alter Trick meist in Assemblersprache verwendet

Ferenc Deak
quelle
Ist das schneller als != 1?
Fiddling Bits
2
In der Antike xorenthielt der Ansatz bei manuellen Baugruppenoptimierungen (x86), wenn ich mich richtig erinnere, weniger Maschinencode und wurde schneller ausgeführt als die entsprechende Zuordnung zu 0... Diese Frage enthält jedoch ein xorUND-Vergleich, sodass ich vielleicht denke, dass dies der !=Fall sein könnte schneller. Ich bin mir jedoch nicht sicher, ob ich eine vom Compiler generierte Assembly sehen müsste.
Ferenc Deak
10
@BitFiddlingCodeMonkey: Nein. Wenn XOR schneller als ein Gleichheitstest auf nativer Ebene wäre, würde Ihr Compiler XORs ausgeben, um die Gleichheit zu testen. Daher sind XORs niemals schneller als Gleichheitstests zur Optimierung von Compilern. Regel 101 zum Schreiben von schnellem Code lautet: "Versuchen Sie nicht, dem Compiler zu helfen. Sie werden am Ende nur unlesbaren Code erstellen, der in der Praxis langsamer ist."
Matt
@fritzone IIRC, die XOR-Tricks hatten mehr mit dem Speichern von Registern, dem Speichern einer Registerlast zu tun, da das Literal in einigen Fällen direkt im OP codiert werden konnte, und einigen subtilen Unterschieden mit Statusflags (aber der größte Teil meiner Assembly war aktiviert 68k und DSP).
mpdonadio
1
@MPD: Normalerweise geht es um das Löschen eines Registers (mindestens bei 386+). xor eax, eax setzt eax in zwei Bytes auf Null, aber mov eax, 0 benötigt drei oder sechs Bytes (abhängig von der Codierung) und die Dekodierung dauert etwas länger als die xor- Form.
Matt
18

Der ^Operator ist bitweise xor. Und 0x1ist die Zahl 1, geschrieben als hexadezimale Konstante.

So x ^ 0x1wertet auf einen neuen Wert, der die gleiche ist wie x, aber mit dem niedrigstwertigen Bit umgedreht.

Der Code vergleicht x nur mit 1 auf sehr verworrene und dunkle Weise.

David Heffernan
quelle
11

Der xor-Operator (exklusiv oder) wird am häufigsten verwendet, um ein oder mehrere Bits zu invertieren. Die Operation besteht darin, zu fragen, ob genau eines der Bits eins ist. Dies führt zu der folgenden Wahrheitstabelle (A und B sind Eingaben, Y ist Ausgaben):

A    B    Y
0    0    0
0    1    1
1    0    1
1    1    0

Nun scheint der Zweck dieses Codes zu sein, zu überprüfen, ob genau das letzte Bit 1 ist und die anderen 0 sind, dies ist gleich if ( x != 1 ). Der Grund für diese obskure Methode könnte sein, dass frühere Bitmanipulationstechniken verwendet wurden und möglicherweise an anderen Stellen im Programm verwendet werden.

Paul
quelle
8

^ist bitweise xor operatorin c. In Ihrem Fall ist x mit 1 xor'ed. Hat beispielsweise xden Wert 10, dann wird die 10d ^ 1d ===> 1010b ^ 0001b = 1011b, 1011b == 11dBedingung wahr.

Chinna
quelle
Tippfehler in Ihrer Antwort. 10 != 1010
Fiddling Bits
@ BitFiddlingCodeMonkey: Tippfehler in Ihrem Kommentar:10 (decimal) == 1010 (binary)
Paul R
6
@PaulR Woher soll jemand wissen, was dezimal und was binär ist, wenn Sie dort kein boder etwas einfügen ?
Fiddling Bits
Wäre 0b1010 nicht die pythonische Art, Dinge zu tun?
TankorSmash
8

Der bitweise Test scheint eine absichtliche Verschleierung zu sein. Wenn es sich bei den zugrunde liegenden Daten jedoch um Unternehmensdaten eines IBM Mainframe-Systems handelt, kann es einfach sein, dass der Code so geschrieben wurde, dass er die Originaldokumentation widerspiegelt. IBM Datenformate reichen bis in die 1960er Jahre zurück und codieren Flags häufig als einzelne Bits innerhalb eines Wortes, um Speicherplatz zu sparen. Während die Formate geändert wurden, wurden Flag-Bytes am Ende der vorhandenen Datensätze hinzugefügt, um die Abwärtskompatibilität aufrechtzuerhalten. In der Dokumentation für einen SMF-Datensatz wird beispielsweise möglicherweise der Assembler-Code angezeigt, mit dem drei einzelne Bits innerhalb von drei verschiedenen Wörtern in einem einzelnen Datensatz getestet werden können, um zu entscheiden, dass es sich bei den Daten um eine Eingabedatei handelt. Ich weiß viel weniger über TCP / IP-Interna, aber dort finden Sie möglicherweise auch Bit-Flags.

nicht definiert
quelle
7

Der Operator ^ ist das bitweise xor (siehe &, |). Das Ergebnis für ein Bitpaar ist:

0 ^ 0 == 0
0 ^ 1 == 1
1 ^ 0 == 1
1 ^ 1 == 0

Also der Ausdruck,

( x ^ 0x1 )

invertiert / kippt das 0. Bit von x (wobei andere Bits unverändert bleiben).

Überlegen Sie, ob x neben 0x0 und 0x1 auch andere Werte haben kann? Wenn x ein einzelnes Bitfeld ist, kann es nur die Werte 0x0 und 0x1 haben. Wenn x jedoch ein int ist (char / short / long / etc), können Bits neben bit0 das Ergebnis des Ausdrucks beeinflussen.

Der angegebene Ausdruck ermöglicht es Bits neben Bit0, das Ergebnis zu beeinflussen.

if ( 0 != ( x ^ 0x1 ) )

Welches hat die gleiche Wahrhaftigkeit wie dieser (einfachere) Ausdruck,

if ( x ^ 0x1 )

Beachten Sie, dass dieser Ausdruck nur Bit0 untersuchen würde.

if( 0x1 & ( x ^ 0x1 ) )

Der dargestellte Ausdruck kombiniert also wirklich zwei Ausdrucksprüfungen.

if( ( x & ~0x1 )  //look at all bits besides bit0
||  ( x ^ 0x1 ) ) //combine with the xor expression for bit0

Wollte der Autor nur Bit0 überprüfen und wollte diesen Ausdruck verwenden?

if( 0x1 & ( x ^ 0x1 ) )

Oder hatte der Autor vor, die Werte für Bit1-BitN und das Xor von Bit0 zu ermitteln?

ChuckCottrill
quelle
7

Ich füge eine neue Antwort hinzu, weil niemand wirklich erklärt hat, wie man die Antwort intuitiv erhält.

Die Umkehrung von +ist -.
Die Umkehrung von ^ist ^.

Wie Sie lösen 0 != x - 1für x? Sie + 1zu beiden Seiten: 0 + 1 != x - 1 + 11 != x.
Wie Sie lösen 0 != x ^ 1für x? Sie ^ 1zu beiden Seiten: 0 ^ 1 != x ^ 1 ^ 11 != x.

user541686
quelle
6

Ich würde vermuten, dass es andere Bits oder Bitfeldwerte gibt x, und dies soll testen, ob nur das niederwertige Bit gesetzt ist. Im Zusammenhang würde ich vermuten, dass dies die Standardeinstellung ist und daher die Codierung dieser und einiger verwandter Elementem (wahrscheinlich teurer zu codierender) Elemente übersprungen werden kann, da beide der Standardwert sein müssen, der in einem Konstruktor oder ähnlichem initialisiert wurde.

Irgendwie muss der Decoder in der Lage sein zu schließen, dass diese Werte fehlen. Wenn sie sich am Ende einer Struktur befinden, kann dies über einen lengthWert erfolgen, der immer vorhanden ist.

Ed Staub
quelle
4

Das XOR ist in der C # -Flag-Aufzählung nützlich. Um ein einzelnes Flag aus dem Enum-Wert zu entfernen, muss der Operator xor verwendet werden (siehe hier) ).

Beispiel:

[Flags]
enum FlagTest { None 0x0, Test1 0x1, Test2 0x2, Test3 0x4}

FlagTest test = FlagTest.Test2 | FlagTest.Test3;
Console.WriteLine(test); //Out: FlagTest.Test2 | FlagTest.Test3
test = test ^ FlagTest.Test2;
Console.WriteLine(test); //Out: FlagTest.Test3
Igrek.
quelle
ABER die Frage ist über C ++, nicht C #
theDmi
@theDmi: ABER AUCH über Bitmanipulation und Bitmaske. Bei der Flaggenaufzählung in C # geht es definitiv um Bitmaske.
Igrek.
Außerdem kann es auch in C ++ nützlich sein. Siehe: Stapel 1 und Stapel 2
Igrek.
Diese Antwort scheint nichts mit der ursprünglichen Frage zu tun zu haben, außer einer Diskussion über den bitweisen XOR-Operator?
Paul R
4

Es gibt viele gute Antworten, aber ich denke gerne einfacher darüber nach.

if ( 0 != ( x ^ 0x1 ) );

Zuerst. Eine if-Anweisung ist nur falsch, wenn das Argument Null ist. Dies bedeutet, dass ein Vergleich ungleich Null sinnlos ist.

if ( a != 0 );
// Same as
if ( a );

Das lässt uns also mit:

if ( x ^ 0x1 );

Ein XOR mit einem. Was für ein XOR tut , ist im Wesentlichen erkennen Bits , die unterschiedlich sind. Wenn also alle Bits gleich sind, wird 0 zurückgegeben. Da 0 falsch ist, wird nur dann false zurückgegeben, wenn alle Bits gleich sind. Es ist also falsch, wenn die Argumente gleich sind, wahr, wenn sie unterschiedlich sind ... genau wie der Operator ungleich .

if ( x != 0x1 );

Tatsächlich besteht der einzige Unterschied zwischen den beiden darin, dass !=0 oder 1 zurückgegeben wird, während ^eine beliebige Zahl zurückgegeben wird, die Wahrhaftigkeit des Ergebnisses jedoch immer dieselbe ist. Eine einfache Möglichkeit, darüber nachzudenken, ist.

(b != c) === !!(b ^ c) // for all b and c

Die letzte "Vereinfachung" ist die Konvertierung 0x1in eine Dezimalzahl von 1. Daher entspricht Ihre Aussage:

if ( x != 1 )
Kevin Cox
quelle
1

^ ist ein bitweiser XOR- Operator

Wenn x = 1

          00000001   (x)       (decimal 1)
          00000001   (0x1)     (decimal 1)
XOR       00000000   (0x0)     (decimal 0)

hier 0 == (x ^ 0x1)

Wenn x = 0

          00000000   (x)       (decimal 0)
          00000001   (0x1)     (decimal 1)
XOR       00000001   (0x1)     (decimal 0)

hier 0! = (x ^ 0x1)

Die Wahrheitstabelle von a xor b:

a           b        a xor b
----------------------------
1           1           0
1           0           1
0           1           1
0           0           0

Der Code bedeutet einfach

akbar ali
quelle
6
Ist es wirklich notwendig, noch eine doppelte Antwort zu posten?
Mysticial
2
Sie können eine andere Antwort sagen, aber nicht duplizieren. Entschuldigung, wenn es Ihnen etwas ausmacht
Akbar Ali
1

Die Standardtechnik, die hier verwendet werden könnte, besteht darin, ein Idiom, wie es im umgebenden Kontext erscheint, aus Gründen der Klarheit zu wiederholen, anstatt es zu verschleiern, indem es durch ein Idiom ersetzt wird, das arithmetisch einfacher, aber kontextuell bedeutungslos ist.

Der umgebende Code kann häufig auf verweisen (x ^ 1), oder der Test fragt möglicherweise: "Wenn Bit 0 umgekehrt wäre, wäre diese Bitmaske leer?".

Angesichts der Tatsache, dass die Bedingung dazu führt, dass etwas encode()bearbeitet wird, kann es sein, dass im Kontext der Standardzustand von Bit 0 durch andere Faktoren invertiert wurde und wir zusätzliche Informationen nur dann codieren müssen, wenn eines der Bits von ihrem Standard abweicht (normalerweise alle Null) ).

Wenn Sie den Ausdruck aus dem Kontext nehmen und fragen, was er bewirkt, übersehen Sie die zugrunde liegende Absicht. Sie können sich auch die Assembly-Ausgabe des Compilers ansehen und feststellen, dass lediglich ein direkter Gleichheitsvergleich mit 1 durchgeführt wird.

sh1
quelle
0

Wie ich die Antworten bisher sehe, fehlt eine einfache Regel für den Umgang mit XORs. Ohne ins Detail zu gehen, was ^und was 0x(und if, und !=usw.) bedeutet, kann der Ausdruck 0 != (x^1)wie folgt überarbeitet werden, indem Folgendes verwendet wird (a^a)==0:

0 != (x^1) <=> [xor left and right side by 1]
(0^1) != (x^1^1) <=>
1 != x
Serge Rogatch
quelle