【问题标题】:Difference between ! and ~ in c#之间的区别!和 ~ 在 C# 中
【发布时间】:2014-02-03 17:30:54
【问题描述】:

当我第一次学习如何编写程序时,我使用了 C。(非常基本的命令行应用程序) 在这两种语言中,您都使用 ! - 运营商通常是这样的:

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

我想在 c# 中做一些位掩码,我想知道“~”运算符。

现在我有点困惑,因为以我自己的理解!和 ~ 应该做同样的事情。

这在 c# 中有效:

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

这不是:(但它确实在 c 中工作并且完全符合我的预期)

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

那么 ~ 和 ! 的区别是什么?他们为什么要分开?

【问题讨论】:

  • 假设true == 0x00000001,当你运行~0x01!0x01时应该更清楚区别。

标签: c# bitwise-operators logical-operators


【解决方案1】:

C# 决定将整数运算与布尔运算完全分开。例如,您不能执行 if(x & 4),而必须执行 if((x & 4) != 0) 才能显式地从整数转换为布尔值。

这与 4 多年使用 C 及其前辈的经验一致,在这些经验中,人们经常犯错误,例如 &ing 两个真值为 true 的值并得到 false,因为虽然它们其中两个都是非零,它们没有共同的非零位。

C 和 C++ 都在其历史后期引入了 bool 类型,以在表示数字或位模式的整数与我们只关心真值但必须兼容的值之间添加更明确的区别使用旧代码。 C# 拥有更加明确的奢侈。

考虑到这一点,C# 的 !~ 与 C 中的完全相同,只是有些东西不再有意义:

在 C 中,! 否定真值。它将 0(假)变为 1(真),并将所有非零(真)变为 0(假)。在 C# 中,这仅适用于 bool,不适用于 int

在 C 中 ~ 产生一个补码;它产生一个值,其中每 1 位变为 0,每 0 位变为 1(例如,0xFFFFFFFF 变为 0,0xF0F0F0F0 变为 0x0F0F0F0F 等等)。在 C# 中,int 有意义,但 bool 没有意义。

如果您想在 C# 中执行与 !someInteger 等效的操作,请执行 someInteger == 0

编辑:

值得注意的是,有时由于运算符被分为“按位”('&'、'|'和'~')和“布尔”('&&'、'||'和' !')。这种区分并不完全正确。

现在,最后三个确实只在布尔上下文中才有意义,因此 C# 对布尔值和整数值进行了更严格的区分,它们不再适用于整数。

'~' 在布尔上下文中确实没有意义('x' 为真的'~x' 将产生一个仍然为真的'x',4294967295 次中有 4294967294 次),因此对于 C#,它不再是应用于布尔值。

'&' 和 '|'保留布尔使用。在 'A()' 和 'B()' 各自返回 bool 的情况下,A() && B() 将仅在 A() 为 false 时调用 B()(即,它“短路”) , A() & B() 在执行 布尔运算之前将始终调用这两种方法。这往往很少见,因为:

    1234563但是我们无论如何都没有失去任何东西,所以这是习惯。(但请考虑,如果B() 非常便宜,那么无论如何调用它的成本可能比分支机构便宜,特别是如果预测错误,请参阅下面的 cmets)。
  1. 有时&& 是强制性的,例如在x != null && x.Length != 0 中,不短路会在第二个参数上引发异常。

  2. 如果确保调用这两个方法非常重要,那么最好在单独的语句中编写代码,以便让其他开发人员(或稍后回来时您自己)清楚这一点。

但是,如果我们要讨论带有布尔参数和整数参数的运算符之间的区别,我们应该包括 |& 的布尔使用,因为它们确实会出现(有时是通过拼写错误!),并且如果人们错误地将“位运算符”和“布尔运算符”分开并忘记有两个符号同时用作两者,则它们可能会引起混淆。

【讨论】:

  • 谢谢!其他答案还可以,但不是我想听到的。因为“一位”的反转(据我所知是技术上保存的布尔型,如 0xFF 或 0x00)类型应该与整数类型的反转相同。
  • 实际上,在 C 语言中 (!0) 的正常值是 0x01。在内部,这在 C# 中也是如此(您可以使用从 bool* 复制到 int* 的不安全操作来测试这一点)。出于这个原因,在用作布尔值但不是布尔值的值上使用~ 作为一个补码(或- 作为双补码)可能会产生令人困惑的结果,因此allowing ++ on bools, but not -- 也是如此。在 VB6 和更早的版本中,真正的布尔值确实是 0xFFFF,原因与您的想法相近,但这仍然可能导致混淆......
  • ... 例如虽然这现在允许对布尔值和整数的操作之间具有更大的一致性(NOT TRUE 导致 FALSE 没有任何不同的操作方式,因为 ~0xFFFF 为 0x0),但仍然存在 4 为真且 2 为真但 4 AND 2 是的问题错误的。重要的是,在 C 中,!1!0xFFFFFF!42 的结果都是 0,与 ~ 不对应。
  • 是的,任何非零都被视为true,但产生 true(例如!false)的操作结果始终为1。确实,我发现强迫其他非零值作为true 是不好的;这在 C# 和大多数 .NET 语言中实际上是不可能的,并且那里的一些代码假定唯一可能的值是 10。上周我在编写的一些 CIL 中遇到了一个有趣的错误,我在其中执行了 C 风格的任何非零为真方法,而我的 NUnit 测试显示“预期:真,但结果:真”。严格来说,这个错误在object.Equals,但我改变了它,因为其他代码可以调用它。
  • 乔恩的好答案。我还要补充一点。在极少数情况下,A() & B() 的性能可能高于 A() && B()&&相当于一个if-then,不仅让代码变大了,还引入了条件分支,这意味着处理器要进行分支预测,也就是说它可以选错,这意味着处理器可以做出其他糟糕的优化决策。如果B() 非常便宜,那么有时不必要地执行此操作的成本小于 添加额外条件分支的成本。
【解决方案2】:

! 是一个布尔反转,它将一个值从true 反转为false,反之亦然。 http://msdn.microsoft.com/en-us/library/f2kd6eb2.aspx

~ 是按位反转,它反转整数值的每一位,如int ihttp://msdn.microsoft.com/en-us/library/d2bd4x66.aspx

http://msdn.microsoft.com/en-us/library/6a71f45d.aspx 有关所有操作员的完整指南。

!~ 之所以分开,是因为他们做的事情不同。

【讨论】:

  • 稍微解释一下可以使这个答案成为更好的答案
【解决方案3】:

~按位非运算符是一元运算符,因为它包含单个操作数。与其他位运算符不同,位版本不使用与类似的布尔运算符相同的符号。为了实现补码,波浪号 (~) 位于要修改的值的左侧。

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

! - 是一个布尔反转,可以为真或假。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-29
    • 1970-01-01
    • 2013-05-02
    • 1970-01-01
    • 1970-01-01
    • 2020-10-17
    • 2010-10-23
    相关资源
    最近更新 更多