~ (bitwise NOT)
Оператор ~ инвертирует все биты числа: каждый 0 становится 1 и наоборот — удобно для сброса битов через маски вида ~(1 << N).
Полная статья
Описание
Побитовый оператор NOT обозначается символом тильды ~ и является унарным — он применяется к одному операнду, стоящему справа от него. В отличие от & и |, которым нужны два операнда, ~ просто переворачивает все биты числа: каждый 0 превращается в 1, а каждый 1 — в 0.
Другими словами:
0 1 operand1
-----
1 0 ~operand1
Пример кода
int a = 103; // двоичное: 0000000001100111
int b = ~a; // двоичное: 1111111110011000 = -104
Как читать результат
Если применить ~ к числу типа int и получить неожиданно отрицательный результат — например, ~103 даст -104 — это не ошибка. Всё дело в том, как целые числа со знаком хранятся в памяти.
В типе int старший бит является знаковым: если он равен 1, число считается отрицательным. Такой способ представления называется дополнением до двух (Twos_complement). После инверсии всех битов знаковый бит тоже меняется, и положительное число превращается в отрицательное.
Полезное правило: для любого целого числа x выражение ~x всегда равно -x - 1. Это прямое следствие дополнения до двух и помогает быстро проверить результат в уме.
Практические замечания
- Тип операнда важен. Результат
~зависит от разрядности типа: дляbyte(8 бит) иint(16 или 32 бита) результат будет разным. Если нужна инверсия только младших 8 бит, используйте явное приведение или маску:~value & 0xFF. - Знаковый бит может удивить. Если переменная имеет тип
intилиlong, инверсия затронет знаковый бит, и положительное число станет отрицательным. Это нормальное поведение, но важно учитывать его при сравнениях и арифметике. - Типичное применение — маски битов. Оператор
~удобен в паре с&, когда нужно сбросить конкретный бит, не трогая остальные:PORTB &= ~(1 << 3)сбрасывает третий бит регистраPORTB. - Не путайте с логическим NOT. Оператор
!— это логическое отрицание:!0даёт1, а!5даёт0. Побитовый~работает с каждым битом числа, а не с его логическим смыслом.
Где применяется
- Управление отдельными битами регистров — сброс нужного бита через маску вида
~(1 << N). - Работа с флагами — инверсия набора флагов для получения «всего, кроме выбранного».
- Контрольные суммы и протоколы — некоторые протоколы передают инвертированный байт как проверочный.
- Работа с PWM и ШИМ — получение дополнительного (инвертированного) сигнала для двухтактных схем.
Примечания и предупреждения
Знаковый бит в целочисленных типах со знаком может приводить к неожиданным результатам, если вы не учитываете дополнение до двух. Если результат ~x кажется неверным — проверьте тип переменной и при необходимости используйте unsigned-тип или явную маску, чтобы ограничить инверсию нужным числом бит.