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

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

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

Я хотел сделать немного битовой маскировки в C#, и мне было интересно узнать об операторе '~'.

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

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

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

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

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

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

3 ответа

Решение

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

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

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

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

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

В С ~ производит свой комплемент; Он выдает значение, при котором каждый 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()' каждый возвращает boolтогда A() && B() буду только звонить B() если A() ложно (то есть это "короткое замыкание"), A() & B() всегда будет вызывать оба метода, прежде чем делать Булева арифметика. Это имеет тенденцию быть редким, потому что:

  1. Большую часть времени звонит B() это просто пустая трата времени, и короткое замыкание может дать нам повышение производительности, начиная от массивного (если B() дорого) так или иначе, но ничего не изменилось, но мы ничего не потеряли, так что это привычка. (Но учтите, что если 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

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

Другие вопросы по тегам