Подтвердить что ты не робот

Разница между! и ~ в С#

Когда я сначала ушел, как писать программы, я использовал C. (очень простые приложения командной строки) На обоих языках вы используете! - оператор обычно выглядит следующим образом:

    if(!true){
       //false..
}

Я хотел сделать некоторую битовую маскировку в С#, и я задавался вопросом о "~" операторе.

Теперь я немного смущен, потому что в своем собственном понимании! и ~ должен делать то же самое.

Это работает в С#:

int i = ~0xffffffff; // i = 0
bool j = !true; // j = false

Это не так: (Но он работает в c и делает именно то, что я ожидал)

int i = !0xffffffff; // i = 0

Итак, что такое различие между ~ и! и почему они отделили их?

4b9b3361

Ответ 1

С# решило полностью отделить целые операции от булевых операций. Вы не можете, например, сделать if(x & 4), вы должны сделать if((x & 4) != 0), чтобы явно перемещаться из целых чисел в booleans.

Это соответствует более чем 4-летнему опыту с C и его предшественниками, в которых люди часто совершали с ним ошибки, такие как и два значения, которые имели значение истинности true и получали false, потому что в то время как они, где оба отличны от нуля, не имели ненулевых битов.

C и С++ представили тип bool в конце своей истории, чтобы добавить более явное различие между целыми числами, которые представляют либо числа, либо битовые шаблоны, и значения, где мы только заботимся об истинных значениях, но должны быть совместимы с более старым кодом. У С# была роскошь быть еще более явной.

Имея это в виду, С# ! и ~ точно такие же, как в C, за исключением того, что некоторые вещи уже не имеют смысла:

В C ! отрицает значение истины. Он превращает 0 (false) в 1 (true) и все ненулевые (true) в 0 (false). В С#, который имеет смысл только с bool, а не с int.

В C ~ получается одно-дополнение; Он генерирует значение, когда каждый 1 бит поворачивается на 0 и каждый 0 бит поворачивается на 1 (например, 0xFFFFFFFF становится 0, 0xF0F0F0F0 становится 0x0F0F0F0F и т.д.). В С#, который имеет смысл с int, но не с bool.

Если вы хотите сделать эквивалент !someInteger в С#, выполните someInteger == 0.

Edit:

Стоит отметить, что иногда возникает некоторая путаница, вызванная разбиением операторов на "поразрядные" ( "&", "|" и "~" ) и "boolean" ('& &', '| | 'и'! '). Это различие не совсем корректно.

Теперь последние три действительно имеют смысл в булевых контекстах, и поэтому, когда С# имеет более строгое разделение между логическими и целочисленными значениями, они больше не применяются к целым числам.

'~' действительно не имеет смысла в булевых контекстах ( "~ x", где "x" - true, будет генерировать "x", который по-прежнему верен, 4294967294 раза из 4294967295), и поэтому с С# он больше не применяется к bools.

'&' и '|' сохраняйте булевское использование. В случае, когда 'A()' и 'B()' возвращают a bool, тогда, когда A() && B() будет вызывать только B(), если A() является ложным (то есть, это "короткие замыкания" ), A() & B() всегда будет вызывать оба метода, прежде чем выполнять арифметику Boolean. Это, как правило, редко, потому что:

  • В большинстве случаев вызов B() - это просто пустая трата времени, и короткое замыкание может дать нам повышение производительности, начиная с массивного (если B() дорого) до того, но мы все-таки ничего не теряли, так что привычка быть в нем. (Но считайте, что если B() очень дешево, стоимость его вызова в любом случае может быть дешевле, чем отрасль, особенно если это неверно предсказано, см. комментарии ниже).

  • Иногда && является обязательным, например, в x != null && x.Length != 0, где не короткое замыкание будет вызывать исключение во втором аргументе.

  • Если это важно, чтобы удостовериться, что оба метода были вызваны, то лучше кодировать это в отдельных инструкциях, чтобы сделать это понятным для других разработчиков (или самостоятельно, когда вы вернетесь позже).

Но если мы поговорим о различии между операторами с логическими и целочисленными аргументами, мы должны включить логическое использование | и &, потому что они появляются (иногда через опечатки!) и они могут вызвать путаницу, если люди ложно отделяют "побитовые операторы" и "логические операторы" и забывают, что есть два символа, которые используются как оба.

Ответ 2

! является булевым инвертированием, он инвертирует значение от true до false и наоборот. http://msdn.microsoft.com/en-us/library/f2kd6eb2.aspx

~ является поразрядным инвертированием, он инвертирует каждый бит интегрального значения, например int i. http://msdn.microsoft.com/en-us/library/d2bd4x66.aspx

см. http://msdn.microsoft.com/en-us/library/6a71f45d.aspx для полного руководства для всех операторов.

Причина, по которой ! и ~ являются отдельными, состоит в том, что они выполняют разные вещи.

Ответ 3

~ Побитовый оператор NOT является унарным оператором, так как он включает в себя один операнд. В отличие от других побитовых операторов, побитовая версия не использует тот же символ, что и аналогичный булевский оператор. Для достижения одного дополнения символ тильды (~) расположен слева от значения, которое необходимо изменить.

byte valueToComplement = 187;                  // 10111011  
byte complement = (byte) ~valueToComplement;   // Result = 68

! - это логическое преобразование, которое может быть истинным или ложным.