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


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

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

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

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

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

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

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

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

Так в чем же разница между ~ и ! и почему они их разделили?

3 24

3 ответа:

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

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

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

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

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

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

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

Правка:

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

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

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

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

  1. В большинстве случаев вызов B() - это просто пустая трата времени., и короткое замыкание может дать нам повышение производительности, начиная от массивного (если B() дорого) до made-no-difference-but-we-didn't-lose-anything-anyway, так что это привычка. (Но учтите, что если B() очень дешево, то стоимость вызова его в любом случае может быть дешевле, чем ветка, особенно если она неправильно интерпретирована, см. комментарии ниже).

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

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

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

! является булевым инвертом, он инвертирует значение из 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 для полного руководства по всем операторам.

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

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

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

! - является логическим инвертом, который может быть либо истинным, либо ложным.