Що означає (x ^ 0x1)! = 0?


183

Я натрапив на наступний фрагмент коду

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

Що x ^ 0x1означає? Це якась стандартна техніка?


97
Обфузація коду цілком стандартна.
raina77ow

47
Це можна вирішити тим самим підходом, що і «нормальне» рівняння: 0 != (x ^ 1)→ xor обидві сторони на 1 → (0 ^ 1) != (x ^ 1 ^ 1)→ спростити →1 != x
Score_Under

4
Я не бачу, як if (1 != x)важко написати.
Адріано Варолі П'яцца

12
Різні коментарі, спочатку @Spook, ясно вказують на те , що typeз xне дано - значить , ми не знаємо , що це ціле число в цій C ++ позначено проблему. Звичайно, якщо це C або xце ціле число, відповідь проста, але це не дано і operator ^існує можливість перевантаження .
chux

11
Я не бачу, як це отримує так багато відгуків ...
laike9m

Відповіді:


277

Операція XOR ( x ^ 0x1) інвертує біт 0. Отже, вираз ефективно означає: якщо біт 0 з x дорівнює 0, або будь-який інший біт x дорівнює 1, то вираз є істинним.

І навпаки, вираз хибний, якщо x == 1.

Отже тест такий самий, як:

if (x != 1)

і тому (імовірно) непотрібно затьмарений.


39
Гей, ти не знаєш контексту. Якщо x - якийсь бітовий прапор, IMO насправді зрозуміліше записати його як зараз, ніж використовувати оператор! =
Spook

40
@Spook: це не просто тестування єдиного бітового прапора - це тестування всієї ширини x. Якщо ви просто хочете перевірити один біт, то є чіткіші ідіоми, такі як використання бітового AND.
Пол Р

115
Непотрібно заплутаний? Хіба ви не знаєте, що наша робота з придушення коду. Якщо ми писали простий код, який кожен міг зрозуміти, то чому, куди піде релігійна святість наших позицій у світі? Ми раптом стали звичайними працівниками, як і всі. Заплутаність по суті необхідна.
Том

31
Насправді Спук має рацію. Тест (x! = 1) не еквівалентний. Код може бути C ++ (а в C ++, ^ може бути оператором, який робить що-небудь). Тож ви не знаєте контексту, @Spook має рацію.
xryl669

82
@TheThom уєт уσυ ωяιТ ιі ¢ ¢єαя тєхт
bobobobo

78
  • ^- побітна операція XOR
  • 0x1знаходиться 1в шістнадцятковій нотації
  • x ^ 0x1буде інвертувати останній біт x(зверніться до таблиці правди XOR за посиланням вище, якщо вам це не зрозуміло).

Отже, умова (0 != ( x ^ 0x1 ))буде істинною, якщо xбільша за 1 або якщо останній біт xдорівнює 0. Що лише залишає х == 1 як значення, при якому умова буде помилковою. Тож це рівнозначно

if (x != 1)

PS Можу додати пекло способу реалізації такої простої умови. Не робіть цього. І якщо вам потрібно написати складний код, залиште коментар . Я вас благаю.


7
Це не так x==0; 4 ^ 0x1правда, але 4==0очевидно помилкова.
Фред Фоо

4
"умова, схоже, дорівнює if (x == 0)", чи не дорівнює x != 1?
Ендрю-Дуфресне

6
Еквівалентність припускає, що xце цілісний тип. Якщо це floatабо double, то я вважаю, що це вираження справдиться для 1.0 <= x < 2.0. І якщо xце визначений користувачем тип, вираз може повернутись істинним, якщо xце юго, кенгуру, день народження композитора або будь-яке число, яке має принаймні три цифри з поточною ціною чаю в Китаї на долар.
supercat

4
@supercat Немає operator^для float/ double.
пухнастий

1
@supercat: Коли потрібна конверсія з плаваючою комою в ціле число, перетворення є неявним (не вимагає синтаксису відливання). Але перетворення побітових операторів не викликає перетворення, вони просто не вдається для типів з плаваючою комою.
Бен Войгт

49

Це може здатися спрощеним поясненням, але якщо хтось хотів би пройти його повільно, це нижче:

^є побітовим оператором XOR в c, c ++ і c #.

Бітовий XOR приймає два бітових шаблони однакової довжини і виконує логічну ексклюзивну операцію АБО на кожній парі відповідних бітів.

Ексклюзивний АБО - це логічна операція, яка виводить true, коли обидва входи відрізняються (один - це правда, інший - помилково).

Таблиця істинності в вигляді виключає Ь :

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

Тож давайте проілюструємо 0 == ( x ^ 0x1 )вираз на двійковому рівні:

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

так:

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

34

Це ексклюзивний оператор АБО (XOR). Щоб зрозуміти, як це працює, можна запустити цей простий код

    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;

Вихід буде

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

Так це вираз

0 != ( x ^ 0x1 )

буде дорівнює істині лише тоді, коли x! = 0x1.

Він не змінює х себе. Він лише перевіряє, чи х дорівнює 0 або 1. цю rxpression можна змінити на

if ( x != 0x1 )

19

Він перевіряє , що xнасправді не 0x1... xorІНГ xз 0x1призведе до 0 , тільки якщо xце 0x1... це старий трюк в основному використовується на мові асемблера


Це швидше, ніж != 1?
Стрічка бітів

2
в давнину, роблячи оптимізацію складання вручну (x86), якщо я правильно пам’ятаю, xorпідхід містив менше машинного коду і виконувався швидше, ніж відповідне завдання 0... однак це питання містить xorІ порівняння, тому я можу подумати, що це !=може бути швидше. Я не дуже впевнений, однак, потрібно було б побачити якийсь компілятор, що генерується.
Ferenc Deak

10
@BitFiddlingCodeMonkey: Ні. Якщо XOR був швидшим, ніж якийсь тест рівності нативного рівня, ваш компілятор видасть XOR для перевірки рівності. Отже, XOR ніколи не швидше, ніж тести рівності на оптимізацію компіляторів. Правило 101 написання швидкого коду полягає в тому, що "не намагайтеся допомогти компілятору. Ви зробите лише нечитабельний код, який на практиці повільніше".
Метт

@fritzone IIRC, трюки XOR мали більше спільного з збереженням регістрів, збереження навантаження в регістрі з / п, в деяких випадках літерал може бути закодований безпосередньо в ОП, а також деякі тонкі відмінності зі статусними прапорами (але більшість моїх збірок була на 68 к і ДСП).
mpdonadio

1
@MPD: Зазвичай це стосується очищення реєстру (принаймні, на 386+). xor eax, eax встановлює eax до нуля в двох байтах, але mov eax, 0 займає три або шість байтів (залежно від кодування), і дешифрувати потрібно трохи більше часу, ніж форма xor .
Метт

18

^Оператор поразрядного виключає. І 0x1це число 1, записане у вигляді шістнадцяткової постійної.

Отже, x ^ 0x1оцінюється до нового значення, яке є таким же, як x, але з найменш значущим бітом, перевернутим.

Код робить не що інше, як порівняння x з 1 в дуже перекрученому і незрозумілому вигляді.


11

Оператор xor (ексклюзивний або) найчастіше використовується для інвертування одного або декількох бітів. Операція полягає в тому, щоб запитати, чи точно один з бітів один, це призводить до наступної таблиці істинності (A і B - входи, Y - вихід):

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

Тепер цільовим кодом, здається, є перевірка, якщо в екзаметі останній біт дорівнює 1, а інші - 0, це дорівнює if ( x != 1 ). Причиною цього незрозумілого методу може бути те, що були використані методи попереднього маніпулювання бітами і, можливо, вони використовуються в інших місцях програми.


8

^розрядно xor operatorв c. У вашому випадку x xor'ed з 1. наприклад xмає значення 10, тоді 10d ^ 1d ===> 1010b ^ 0001b = 1011b, 1011b == 11dумова стає істинною.


Одрукуйте свою відповідь. 10 != 1010
Fiddling Bits

@BitFiddlingCodeMonkey: друкуємо у вашому коментарі:10 (decimal) == 1010 (binary)
Paul R

6
@PaulR Як хто-небудь повинен знати, що таке десятковий і що двійковий, якщо ви не ставите туди bчи щось там?
Fiddling Bits

хіба 0b1010 не був би піфонічним способом вчинків?
TankorSmash

8

Бітовий тест видається навмисним заплутуванням, але якщо основні дані - це корпоративні дані з системи мейнфреймів IBM, то може бути просто те, що код був написаний для відображення оригінальної документації. Формати даних IBM відносяться до 1960-х років і часто кодують прапори як одиничні біти в слові, щоб зберегти сховище. У міру зміни форматів байти прапорів додавались в кінці існуючих записів, щоб підтримувати сумісність ззаду. Документація для запису SMF, наприклад, може показувати код мови складання для тестування трьох окремих бітів в межах трьох різних слів в одному записі, щоб вирішити, що дані були вхідним файлом. Я знаю набагато менше про внутрішні протоколи TCP / IP, але ви також можете знайти там бітові прапори.


7

Оператор ^ - порозрядний-xor (див. &, |). Результат для бітної пари -

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

Отже, вираз,

( x ^ 0x1 )

інвертує / перевертає 0-й біт x (інші біти залишаються незмінними).

Поміркуйте, чи може мати x крім значень 0x0 та 0x1? Коли x є єдиним бітовим полем, воно може мати лише значення 0x0 та 0x1, але коли x є int (char / short / long / тощо), біти, крім bit0, можуть впливати на результат вираження.

Даний вираз дозволяє бітам поруч з біт0 впливати на результат,

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

Який має аналогічну правдивість, як цей (простіший) вираз,

if ( x ^ 0x1 )

Зауважте, що цей вираз буде вивчати лише біт0,

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

Отже, вираз, як представлено, насправді поєднує дві перевірки вираження,

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

Чи автор мав намір перевірити лише bit0 і мав намір використовувати цей вираз,

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

Або автор мав намір вивести значення для bit1-bitN та xor bit0?


7

Я додаю нову відповідь, тому що ніхто не пояснив, як зрозуміти відповідь інтуїтивно.

Зворотним +є -.
Зворотним ^є ^.

Як ви вирішуєте 0 != x - 1для x? Ви + 1в обидві сторони: 0 + 1 != x - 1 + 11 != x.
Як ви вирішуєте 0 != x ^ 1для x? Ви ^ 1в обидві сторони: 0 ^ 1 != x ^ 1 ^ 11 != x.


6

Я б здогадався, що в ньому є інші біти або значення бітового поля x, і це призначено для перевірки того, що встановлено лише біт низького порядку. У контексті я б здогадався, що це за замовчуванням, і тому кодування цього та деяких пов'язаних m(можливо більш дорогих для кодування) може бути пропущено, оскільки вони мають бути типовим значенням, ініціалізованим у конструкторі чи подібному.

Якимось чином декодер повинен мати можливість зробити висновок про відсутність цих значень. Якщо вони знаходяться в кінці якоїсь структури, це може бути передано через lengthзначення, яке завжди присутнє.


4

XOR корисний у переліку C # прапор. Щоб видалити один прапор зі значення перерахунку, необхідно використовувати оператор xor (посилання тут )

Приклад:

[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

А ось питання стосується C ++, а не C #
theDmi

@theDmi: АЛЕ ТАКОЖ про маніпуляцію бітом та біт-маску. Енум прапорця в C #, безумовно, стосується бітмаски.
Ігрек.

Плюс це може бути корисним і для C ++. Див.: Стек 1 і Стек 2
Ігрек.

Ця відповідь, схоже, не має нічого спільного з оригінальним запитанням, окрім обговорення бітового оператора XOR?
Пол Р

4

Є багато хороших відповідей, але мені подобається думати про це простіше.

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

Поперше. Оператор if є хибним, лише якщо аргумент дорівнює нулю. Це означає, що порівнювати, що не дорівнює нулю, безглуздо.

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

Отже, це залишає нас:

if ( x ^ 0x1 );

XOR з одним. Що XOR робить, це по суті виявити різні біти. Отже, якщо всі біти однакові, він поверне 0. Оскільки 0 є помилковим, єдиний раз, коли він поверне помилковий, це якщо всі біти однакові. Тож буде помилковим, якщо аргументи однакові, правдиві, якщо вони різні ... так само, як оператор, не рівний оператору.

if ( x != 0x1 );

Якщо насправді, єдина відмінність між ними - це !=повернення 0 або 1, тоді як ^поверне будь-яке число, але надійність результату завжди буде однаковою. Простий спосіб подумати над цим.

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

Остаточне "спрощення" - це перетворення 0x1в десятковий, який дорівнює 1. Тому ваше твердження еквівалентно:

if ( x != 1 )

1

^ - побітовий оператор XOR

Якщо х = 1

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

тут 0 == (x ^ 0x1)

Якщо х = 0

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

тут 0! = (x ^ 0x1)

Таблиця істинності xor b:

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

Код просто означає


6
Чи справді потрібно опублікувати ще одну повторювану відповідь?
Містичний

2
ви можете сказати іншу відповідь, але не дублювати. вибачте, якщо ви не проти
akbar ali

1

Стандартна методика, яка може бути використана тут, - це повторити ідіому так, як вона з’являється в навколишньому контексті для наочності, а не придушувати її, замінюючи її на ідіому, яка є арифметично простішою, але контекстуально безглуздою.

Навколишній код може часто посилатися на (x ^ 1)або тест може запитати "якщо біт 0 був навпаки, чи була б ця бітова маска порожньою?".

Враховуючи, що умова викликає щось encode() редагування, можливо, в контексті стан за замовчуванням біт 0 був інвертований іншими факторами, і нам потрібно лише кодувати додаткову інформацію, якщо будь-який з бітів відхиляється від замовчування (як правило, всі нулі ).

Якщо ви виймаєте вираз із контексту і запитуєте, що він робить, ви не помічаєте основного наміру. Ви можете так само добре подивитися на висновок збірки з компілятора і побачити, що він просто робить пряме порівняння рівності з 1.


0

Як я бачу, відповіді поки що пропускають просте правило поводження з XORs. Не вникаючи в подробиці, що ^і що 0xозначає (і ifта !=ін.), Вираз 0 != (x^1)можна переробити так, використовуючи той факт, що (a^a)==0:

0 != (x^1) <=> [xor left and right side by 1]
(0^1) != (x^1^1) <=>
1 != x
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.