【问题标题】:What is the difference between ~~x and !!x in C?C中的~~x和!!x有什么区别?
【发布时间】:2016-02-04 15:37:56
【问题描述】:

我正在尝试检查int x 是否有任何位等于1,答案是!!x。我用谷歌搜索了一下,没有找到任何关于为什么这是正确的。

假设我有一个号码x1010!x 会是什么? !x~x 有什么区别?

【问题讨论】:

  • 您是否在任何地方阅读过~! 运算符的描述(如C 书)?如果是这样,您觉得难以理解的具体是什么?
  • 做的目的例如!!x 是得到一个数字真假值。如果x 不为零,则!!x 将是1。对按位否定运算符 ~ 做同样的事情是没有意义的。
  • 这是写太易读的x != 0的两种混淆方式。提示:为了最大程度地混淆,写??-??-x。然后你几乎可以肯定没有人,包括你自己,知道代码的作用。任务完成。
  • ! 是一个逻辑非,如果运算符为FALSE,则产生TRUE 结果。 ~ 是一个 boolean not,它对运算符逐位执行布尔否定。因为在 C 中只有值 0 被认为是 FALSE 而所有其他值都被认为是 TRUE 操作 !x 将是 TRUE 仅当 x==0 时,然后再次逻辑反转 !!x 将是 FALSE 如果 @ 987654348@ 和 TRUE 如果任何位为 1。

标签: c bitwise-operators logical-operators negation


【解决方案1】:

! 是一个逻辑运算符,它取标量类型操作数的

引用C11,第 §6.5.3.3 章,一元算术运算符

逻辑否定运算符!的结果是0,如果其操作数的值比较 不等于 0,如果其操作数的值比较等于 0,则为 1。结果的类型为 int。 [...]

OTOH,~ 是一个按位运算符,对整数类型的操作数执行按位求反。

相关,

~ 运算符的结果是其(提升的)操作数的按位补码(即 当且仅当转换的操作数中的相应位为 没有设置)。对操作数执行整数提升,结果为 提升型。 [...]

例如,考虑二进制数10

  • !100
  • ~1001

编辑:

FWIW,你用!!,得到的结果不是0就是1。OTOH,你用~~,你取回操作数的原始值。

【讨论】:

  • 立即获取。谢谢:D
  • @Anna 不,你将拥有0
  • @Anna 不,在 C 中,每个非零值都是“真”,只有零是“假”。
  • @Joachim Pileborg 同意,即使 Not-A-Number double 是“真实的”。
【解决方案2】:

!x 的可能取值范围是 0 和 1。

~(按位补码)与其域具有相同的范围。

所以~~x 将恢复x,但!!x 不一定会这样做。

【讨论】:

  • 我不太确定~~x 会恢复。操作数有隐式提升,结果类型为(有符号)int。如果x 恰好是unsigned char,那就太糟糕了。如果您编写非常奇怪的代码,您往往会遇到同样奇怪的错误。
  • 这是一个非常好的观点。我也在考虑 ~~ 一个有符号的负零。
  • ~ 实际上并不关心签名,它的级别要低得多。但是,如果您将它与其他会影响符号位的东西一起使用,您可能会遇到严重的错误。例如unsigned char x=1; if( ~(~x >> 1) > 0)。没有人知道这样的代码会做什么。 ~ 运算符通常非常危险。
【解决方案3】:

我正在尝试检查 int x 是否有任何位等于 1,答案是 !!x [...]

不,“答案”(即用 C 编写此检查的正确方法)只是 x != 0。这更清楚,不会让读者思考。使用两个逻辑反转计算相同的值,但不太清楚。

引用 C11 规范草案,我们有:

逻辑否定运算符! 如果其操作数的值比较不等于0,则结果为0,如果其操作数的值比较等于0,则为1。结果类型为int。表达式!E 等价于(0==E)

所以,真的没有任何区别。

此外,对于负零,标准要求

对于任何整数类型,所有位都为零的对象表示应是该类型中值为零的表示。

因此,检查整数的“所有位为零”实际上与比较(不等于)0 相同。

【讨论】:

  • 这是一个很好的答案。我正在与这个想法搏斗!不适用于有符号负零。
【解决方案4】:

! : 是一个逻辑操作符,操作时只给出truefalse作为结果。它将 true 转换为 false 并将 false 转换为 true
~ :是一个逐位否定运算符,即如果某个值的特定位为 0,它将将该位翻转为 1,反之亦然。请注意,它不对整个值进行操作,它仅对位进行操作。

在 C 中,只有数值 0(即 1 字节二进制等效值:00000000)在逻辑上是 false,其他都是 true。任何在其二进制等效项中即使有一个位等于 1 的值都是正确的。所以,

/*Use and explanation of !x*/

int x = 1; //binary equivalent: 00000001 is logically true. it can be checked as follows
if (x) // if statement coerces x to boolean equivalent which is true.
    printf("%d is true", x);

上面代码sn-p中的printf语句会被执行。

现在,当 x (i.e. !x) 上未使用逻辑运算符时,结果为 false,因为 x ( =1 ) 在逻辑上为 true。使用它两次(即 !!x)将使其再次为真
注意:第一次使用它会导致两件事

  1. 导致将值 1 类型转换为等效布尔值(即 true)。
  2. 将布尔值(从第 1 步)更改为相反的值(即 false)。

所以,基本上非逻辑运算符可以用来检查某事是真还是假。使用它两次会返回与被检查值等效的实际布尔值。

/*Use case of ~x (bit-wise negation operator)*/
int x = 1; //binary equivalent: 00000001
int y = ~x; //Now, y will be ~x i.e. 11111110. it can be checked as follows.

printf("%d: value after operation of bit-wise operator", y);
//The printf statement will print decimal equivalent of 11111110 i.e. -2.

y = ~y; // i.e. y = ~~x, this will again flip the bits and make y equal to 1 i.e. 00000001.
printf("%d: value after double operation of bit-wise operator", y);

因此,当需要检查某个值中的任何位是否为1时,基本上意味着检查该值是否在逻辑上true。这可以使用 if 语句(如上所示)或使用偶数个逻辑非运算符来检查,如下所示

int x = 1;
if(!!x)
  printf("x is true");

【讨论】:

    【解决方案5】:

    C 中的 NOT 逻辑运算由运算符 ! 表示。
    在 C 中,每个 null 值都表示 FALSE(如 0、0.0 或空指针常量 NULL)。 OTOH,每个非空都被认为是TRUE
    逻辑取反将逻辑值取反,从而将整数值 0 中的每个非零值转换为整数值 1,并且将整数值 1 中的每个零值转换。
    那么,双重否定只能是 0 或 1。

    现在,如果一个对象表示一个算术值,当且仅当该值是 0 或 0.0 时,它的所有位都是 0。所以这样一个对象的否定等于!0,即1。另外,如果像10101010这样的对象,其位不全为0,只是一个非空值,那么它的否定是0(即@ 987654323@)。

    最后,你有!!0 == 0!!(non-zero-value) == 1

    C 中的按位否定由运算符~ 表示。
    在这种情况下,对每个分离的位执行否定操作。
    例如:~11100111 == 00011000

    因此,如果您应用 按位否定运算符 两次,则恢复原始值:~~x == x

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-08-24
      • 2011-05-10
      • 2012-08-09
      • 2016-07-23
      相关资源
      最近更新 更多