Разница между ними! и ~ в 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# принято решение полностью отделить целочисленных операций из логических операций. Вы не можете, например, сделать
Это согласуется с более чем 4-х десятилетним опытом работы с C и его предшественниками, в котором люди часто совершали ошибки с ним, такие как &ing два значения, которые имели значение истинностиif(x & 4)
вы должны сделатьif((x & 4) != 0)
, чтобы явно перейти от целых чисел к логическим.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()
всегда будет вызывать оба метода, прежде чем делать∧
Булеву арифметику. Это имеет тенденцию быть редким, потому что:Но если мы собираемся говорить о разнице между операторами с булевыми и целочисленными аргументами, мы должны включить логическое использование
В большинстве случаев вызов
B()
- это просто пустая трата времени., и короткое замыкание может дать нам повышение производительности, начиная от массивного (еслиB()
дорого) до made-no-difference-but-we-didn't-lose-anything-anyway, так что это привычка. (Но учтите, что еслиB()
очень дешево, то стоимость вызова его в любом случае может быть дешевле, чем ветка, особенно если она неправильно интерпретирована, см. комментарии ниже).Иногда
&&
является обязательным, например, вx != null && x.Length != 0
, где не короткое замыкание вызвало бы исключение на втором аргумент.Если это так важно, чтобы убедиться, что оба метода были вызваны, то лучше кодировать, чтобы сделать это в отдельных операторах, чтобы сделать это понятным для других разработчиков (или себя, когда вы вернетесь позже).
|
и&
, потому что они действительно возникают (иногда через опечатки!), и они могут вызвать путаницу. если люди ошибочно разделяют "побитовые операторы" и "булевы операторы" и забывают, что есть два символа, которые используются как оба.
!
является булевым инвертом, он инвертирует значение из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
!
- является логическим инвертом, который может быть либо истинным, либо ложным.