Cosa significa (x ^ 0x1)! = 0?


183

Mi sono imbattuto nel seguente frammento di codice

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

Cosa x ^ 0x1significa? È una tecnica standard?


97
L'offuscamento del codice è abbastanza standard.
raina77ow,

47
Questo può essere risolto con lo stesso approccio di un'equazione "normale": 0 != (x ^ 1)→ xo entrambi i lati di 1 → (0 ^ 1) != (x ^ 1 ^ 1)→ semplifica →1 != x
Score_Under

4
Non vedo quanto if (1 != x)sia difficile scrivere.
Adriano Varoli Piazza

12
Vari commenti, prima di @Spook, sottolineano chiaramente che typeof xnon viene fornito, quindi non sappiamo che questo è un numero intero in questo problema con tag C ++. Certo, se questo è C o xè un numero intero, la risposta è semplice, ma non è un dato e operator ^esiste la possibilità di sovraccarico .
chux - Ripristina Monica il

11
Non vedo come questo ottenga così tanti voti ...
laike9m

Risposte:


277

L'operazione XOR ( x ^ 0x1) inverte il bit 0. Quindi l'espressione significa effettivamente: se il bit 0 di x è 0, o qualsiasi altro bit di x è 1, allora l'espressione è vera.

Viceversa, l'espressione è falsa se x == 1.

Quindi il test è lo stesso di:

if (x != 1)

ed è quindi (discutibilmente) inutilmente offuscato.


39
Ehi, non conosci il contesto. Se x è una sorta di bit flag, in realtà è IMO più chiaro scriverlo come è ora che usare l'operatore! =.
Spook,

40
@Spook: non sta solo testando un flag a bit singolo, ma sta testando l'intera larghezza di x. Se vuoi solo testare un singolo bit, allora ci sono modi di dire più chiari, come usare un AND bit per bit.
Paolo R

115
Inutilmente offuscata? Non sai che è nostro compito offuscare il codice. Se scrivessimo un semplice codice che chiunque potesse capire, perché, dove andrebbe la santità religiosa delle nostre posizioni nel mondo? Saremmo improvvisamente lavoratori comuni come tutti gli altri. L'offuscamento è intrinsecamente necessario.
Thom,

31
In realtà Spook ha ragione. Il test (x! = 1) non è equivalente. Il codice può essere C ++ (e in C ++, ^ può essere un operatore che fa qualsiasi cosa). Quindi non conosci il contesto, @Spook ha ragione.
xryl669,

82
@TheThom уєт уσυ ωяιтє ιи ¢ ℓєαя тєχт
bobobobo

78
  • ^è l' operazione XOR bit a bit
  • 0x1è 1in notazione esadecimale
  • x ^ 0x1inverte l'ultimo bit di x(fare riferimento alla tabella di verità XOR nel link sopra se non è chiaro per te).

Pertanto, la condizione (0 != ( x ^ 0x1 ))sarà vera se xè maggiore di 1 o se l'ultimo bit di xè 0. Ciò lascia solo x == 1 come valore per il quale la condizione sarà falsa. Quindi è equivalente a

if (x != 1)

PS Un inferno di un modo per implementare una condizione così semplice, potrei aggiungere. Non farlo. E se devi scrivere un codice complicato, lascia un commento . Ti prego.


7
Non lo è x==0; 4 ^ 0x1è vero, ma 4==0ovviamente è falso.
Fred Foo,

4
"condizione sembra essere uguale a if (x == 0)", non è uguale a x != 1?
Andrew-Dufresne,

6
L'equivalenza presuppone che xsia un tipo integrale. Se è un floato double, allora credo che l'espressione darebbe valore per 1.0 <= x < 2.0. E se xè un tipo definito dall'utente, l'espressione potrebbe tornare vera se xè uno Yugo, un canguro, il compleanno del famoso compositore o qualsiasi numero che condivide almeno tre cifre con l'attuale prezzo in dollari del tè in Cina.
supercat

4
@supercat Non c'è operator^per float/ double.
soffice

1
@supercat: quando viene richiesta una conversione da virgola mobile a intero, la conversione è implicita (non richiede la sintassi del cast). Ma nessuna conversione è innescata da operatori bit a bit, semplicemente falliscono per i tipi a virgola mobile.
Ben Voigt,

49

Questa può sembrare una spiegazione semplificata, ma se qualcuno vorrebbe affrontarla lentamente è sotto:

^è un operatore XOR bit a bit in c, c ++ e c #.

Un XOR bit a bit prende due bit pattern di uguale lunghezza ed esegue l'operazione OR esclusiva logica su ciascuna coppia di bit corrispondenti.

OR esclusivo è un'operazione logica che genera true ogni volta che entrambi gli input differiscono (uno è vero, l'altro è falso).

La tabella della verità di a xor b :

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

Quindi illustriamo l' 0 == ( x ^ 0x1 )espressione a livello binario:

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

così:

   0 == ( x ^ 0x1 )    =>    x == 1
   0 != ( x ^ 0x1 )    =>    x != 1

34

È un operatore OR esclusivo (XOR). Per capire come funziona puoi eseguire questo semplice codice

    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;

L'output sarà

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

Quindi questa espressione

0 != ( x ^ 0x1 )

sarà uguale vero solo quando x! = 0x1.

Non cambia x stesso. Controlla solo se x è uguale a 0 o 1. questa rxpression può essere cambiata in

if ( x != 0x1 )

19

Verifica che in xrealtà non 0x1... xoring xcon 0x1comporterà 0 solo se xè 0x1... questo è un vecchio trucco usato principalmente nel linguaggio assembly


È più veloce di != 1?
Fiddling Bits

2
nei tempi antichi mentre facevo ottimizzazioni di assemblaggio manuali (x86) se ricordo correttamente l' xorapproccio conteneva meno codice macchina ed era eseguito più velocemente del corrispondente compito di 0... tuttavia questa domanda contiene un xorAND un confronto, quindi potrei pensare che !=potrebbe essere Più veloce. Non sono così sicuro, tuttavia, avrebbe bisogno di vedere alcuni assembly generati dal compilatore.
Ferenc Deak,

10
@BitFiddlingCodeMonkey: No. Se XOR fosse più veloce di un test di uguaglianza di livello nativo, il compilatore emetterebbe XOR per verificare l'uguaglianza. Quindi, gli XOR non sono mai più veloci dei test di uguaglianza sull'ottimizzazione dei compilatori. La regola 101 di scrivere codice veloce è "non provare ad aiutare il compilatore. Finirai solo per creare codice illeggibile che è più lento nella pratica".
Matt,

@fritzone IIRC, i trucchi di XOR avevano più a che fare con il salvataggio dei registri, il salvataggio di un carico di registro b / c il letterale poteva essere codificato direttamente nell'OP in alcuni casi e alcune sottili differenze con i flag di stato (ma la maggior parte del mio assembly era attiva 68k e DSP).
mpdonadio,

1
@MPD: normalmente ha a che fare con la cancellazione di un registro (almeno su 386+). xor eax, eax imposta eax su zero in due byte, ma mov eax, 0 richiede tre o sei byte (a seconda della codifica) e impiega un po 'più tempo a decodificare rispetto alla forma xor .
Matt,

18

L' ^operatore è bit per bit o. Ed 0x1è il numero 1, scritto come costante esadecimale.

Quindi, x ^ 0x1restituisce un nuovo valore uguale a x, ma con il bit meno significativo invertito.

Il codice non fa altro che confrontare x con 1, in modo molto contorto e oscuro.


11

L'operatore xor (esclusivo o) è più comunemente usato per invertire uno o più bit. L'operazione è chiedere se esattamente uno dei bit è uno, questo porta alla seguente tabella di verità (A e B sono input, Y è output):

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

Ora lo scopo di questo codice sembra essere quello di verificare se l'ultimo bit è 1, e gli altri sono 0, questo è uguale if ( x != 1 ). La ragione di questo oscuro metodo potrebbe essere che sono state utilizzate tecniche di manipolazione dei bit precedenti e che forse sono state utilizzate in altri punti del programma.


8

^è bitwise xor operatorin c. Nel tuo caso x è xor con 1. ad esempio xha il valore 10, quindi la 10d ^ 1d ===> 1010b ^ 0001b = 1011b, 1011b == 11dcondizione diventa vera.


Errore di battitura nella tua risposta. 10 != 1010
Fiddling Bits

@BitFiddlingCodeMonkey: errore di battitura nel tuo commento:10 (decimal) == 1010 (binary)
Paul R

6
@PaulR Come si può sapere che cosa è decimale e che cosa è binario se non si inserisce uno bo qualcosa lì?
Fiddling Bits

0b1010 non sarebbe il modo Pythonic di fare le cose?
TankorSmash,

8

Il test bit a bit sembra essere un offuscamento deliberato, ma se i dati sottostanti sono dati aziendali da un sistema mainframe IBM potrebbe semplicemente essere che il codice è stato scritto per riflettere la documentazione originale. I formati di dati IBM risalgono agli anni '60 e spesso codificano i flag come bit singoli all'interno di una parola per risparmiare memoria. Man mano che i formati venivano modificati, i byte flag venivano aggiunti alla fine dei record esistenti per mantenere la compatibilità con le versioni precedenti. La documentazione per un record SMF, ad esempio, potrebbe mostrare il codice del linguaggio assembly per testare tre singoli bit all'interno di tre parole diverse in un singolo record per decidere che i dati fossero un file di input. So molto meno degli interni TCP / IP, ma qui puoi trovare anche bit flag.


7

L'operatore ^ è bit-xor (vedi &, |). Il risultato per una coppia di bit è,

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

Quindi l'espressione,

( x ^ 0x1 )

inverte / inverte il 0o bit di x (lasciando invariati gli altri bit).

Considera se x può avere valori oltre a 0x0 e 0x1? Quando x è un campo a bit singolo, può avere solo valori 0x0 e 0x1, ma quando x è un int (char / short / long / etc), i bit oltre a bit0 possono influenzare il risultato dell'espressione.

L'espressione fornita consente ai bit accanto a bit0 di influire sul risultato,

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

Che ha una veridicità equivalente come questa (più semplice) espressione,

if ( x ^ 0x1 )

Nota che questa espressione esaminerebbe solo bit0,

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

Quindi l'espressione così presentata combina davvero due controlli di espressione,

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

L'autore intendeva controllare solo bit0 e intendeva usare questa espressione,

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

O l'autore aveva intenzione di ottenere i valori per bit1-bitN e xor di bit0?


7

Sto aggiungendo una nuova risposta perché nessuno ha davvero spiegato come ottenere la risposta in modo intuitivo.

L'inverso di +è -.
L'inverso di ^è ^.

Come si risolve 0 != x - 1per x? Da + 1entrambe le parti: 0 + 1 != x - 1 + 11 != x.
Come si risolve 0 != x ^ 1per x? Da ^ 1entrambe le parti: 0 ^ 1 != x ^ 1 ^ 11 != x.


6

Immagino che ci siano altri bit o valori del campo bit in x, e questo ha lo scopo di testare che è impostato solo il bit di ordine basso. Nel contesto, immagino che questo sia il valore predefinito e che quindi la codifica di questo e di alcuni relativi m(probabilmente più costosi da codificare) possa essere ignorata, perché devono essere entrambi il valore predefinito, inizializzati in un costruttore o simili.

In qualche modo il decodificatore deve essere in grado di dedurre che questi valori mancano. Se si trovano alla fine di qualche struttura, potrebbero essere comunicati tramite un lengthvalore sempre presente.


4

XOR è utile nell'enumerazione del flag C #. Per rimuovere il singolo flag dal valore enum è necessario utilizzare l'operatore xor (riferimento qui )

Esempio:

[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

MA la domanda riguarda C ++, non C #
theDmi

@theDmi: MA ANCHE sulla manipolazione e la maschera di bit. Flag enum in C # è sicuramente una questione di bitmask.
Igrek.

Inoltre può essere utile anche in C ++. Vedi: Stack 1 e Stack 2
Igrek.

Questa risposta non sembra avere nulla a che fare con la domanda originale, a parte qualche discussione sull'operatore XOR bit a bit?
Paul R

4

Ci sono molte buone risposte ma mi piace pensarci in un modo più semplice.

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

Prima di tutto. Un'istruzione if è falsa solo se l'argomento è zero. Ciò significa che il confronto non uguale a zero non ha senso.

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

Quindi questo ci lascia con:

if ( x ^ 0x1 );

Uno XOR con uno. Quello che fa uno XOR è essenzialmente rilevare bit diversi. Quindi, se tutti i bit sono uguali, verrà restituito 0. Poiché 0 è falso, l'unica volta che restituirà falso è se tutti i bit sono uguali. Quindi sarà falso se gli argomenti sono gli stessi, vero se sono diversi ... proprio come il non uguale all'operatore.

if ( x != 0x1 );

In realtà, l'unica differenza tra i due è che !=restituirà 0 o 1, mentre ^restituirà qualsiasi numero, ma la verità del risultato sarà sempre la stessa. Un modo semplice per pensarci è.

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

La "semplificazione" finale sta convertendo 0x1in decimale che è 1. Pertanto la tua affermazione equivale a:

if ( x != 1 )

1

^ è un operatore XOR bit a bit

Se x = 1

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

qui 0 == (x ^ 0x1)

Se x = 0

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

qui 0! = (x ^ 0x1)

La tabella della verità di a xor b:

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

Il codice significa semplicemente


6
È davvero necessario pubblicare ancora un'altra risposta duplicata?
Mistico il

2
puoi dire un'altra risposta ma non duplicare. scusate se vi dispiace
Akbar ali

1

La tecnica standard che potrebbe essere utilizzata, qui, è di ripetere un linguaggio come appare nel contesto circostante per chiarezza, piuttosto che offuscarlo sostituendolo con un linguaggio che è aritmeticamente più semplice ma contestualmente insignificante.

Il codice circostante può fare spesso riferimento (x ^ 1)o il test potrebbe chiedere "se il bit 0 fosse il contrario, questa maschera di bit sarebbe vuota?".

Dato che la condizione causa la modifica di qualcosa encode(), è possibile che nel contesto lo stato predefinito del bit 0 sia stato invertito da altri fattori, e abbiamo bisogno di codificare solo informazioni aggiuntive se uno qualsiasi dei bit si discosta dal loro valore predefinito (normalmente tutto zero ).

Se togli l'espressione dal contesto e chiedi cosa fa, trascuri l'intenzione di fondo. Potresti anche guardare l'output dell'assembly dal compilatore e vedere che fa semplicemente un confronto diretto sull'uguaglianza con 1.


0

Dal momento che vedo le risposte finora manca una semplice regola per la gestione di messaggi di posta XORelettronica. Senza entrare nei dettagli cosa ^e cosa 0xsignifichi (e if, !=ecc.), L'espressione 0 != (x^1)può essere rielaborata come segue usando il fatto che (a^a)==0:

0 != (x^1) <=> [xor left and right side by 1]
(0^1) != (x^1^1) <=>
1 != x
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.