【问题标题】:What is "!!" in C? [duplicate]什么是 ”!!”在 C 中? [复制]
【发布时间】:2013-01-23 00:04:30
【问题描述】:

我遇到过以下sn-p:

pt->aa[!!(ts->flags & MASK)] = -val;
  1. !!(双感叹号/感叹号/两个 NOT 运算符)在 c 中代表什么?
  2. 不是(!!NULL) == NULL吗?

【问题讨论】:

  • 示例:在我的代码“Decimal to Binary: Size independent: First Method”中,我使用!!int 转换为01
  • 另外请注意这段代码是错误的。问题 1:使用 bool 作为数组索引。问题2:奇怪!语法,只会让读者感到困惑(正如我们从这个问题中可以看出的那样)。问题3:用一个不必要的复杂表达式计算数组索引,它应该已经移动到自己的一行。所有这些都指向同一件事:我怀疑我们有一个程序员认为他们非常聪明,但实际上在正确的程序设计和代码维护方面需要学习很多东西。
  • 说到可能的重复提名,请记住C和C++是两种不同的语言。因此,我认为有两个独立的问题和独立的答案是合理的。即使今天的语义相似,未来的标准也可能会改变这种状态。
  • Jan 是正确的,链接副本的答案对于 C 是不正确的。

标签: c gcc boolean boolean-expression


【解决方案1】:

! 是否定的。所以!!是否定的否定。重要的是结果将是int

  • !!x 如果x == 0!!0,那就是!1,那就是0
  • !!x 如果x != 0!!(!0),即为!!1,即为!0,即为1

!! 通常用于将任何非零值转换为 1,同时确定 0 仍然是 0。

事实上,!!NULL == NULL,因为!!NULL == !!0!!0 == !1,最后是!1 == 0

因此,在您引用的一小段代码中,如果括号中的表达式的值为NULL,则数组下标将为0,否则为1

【讨论】:

  • 结果值为01 类型int
  • 如果NULL0(!!NULL) == NULL 为真。如果NULL((void*)0),您可能会收到指向整数比较的指针警告。使用!! 的全部意义在于将“truey”和“falsy”表达式结果转换为整数。
  • !!无论 NULL 的类型如何,NULL 都不应该是一个警告。 !ptr 是正常用法。
  • @SandyLee:不完全是。 !!false0!!true1
  • 关于 NULL 的部分是不正确的......即使除了 (void*) 警告之外,有可能(但非常罕见)有一台空指针的值非零的计算机,所以 C 标准允许 NULL 是任何值,例如它可以是(void*)INT_MAX,这会使你的陈述为假。我不确定有多少百分比的 C 代码无法在这样的系统上正确运行,但没有必要鼓励人们做出这种非标准假设并编写更多非标准代码。
【解决方案2】:

它将数字转换为规范的布尔值。

请注意,在这种情况下这样做很关键,因为结果被用于索引数组。

【讨论】:

    【解决方案3】:

    它通常(ab)用于通过重复应用布尔非运算符! 将任何值转换为ints 0 或1。

    例如:!56 为 0,因为 56 被视为布尔值时为“真”。这意味着 !!56 是 1,因为 !0 是 1。

    【讨论】:

    • 你说“滥用”,但这是一个常见的成语。作为简洁的替代方案,您有什么建议?
    • @PCLuddite 好吧,我确实说过“(ab)used”,暗示滥用指控有点开玩笑”。我可能会推荐pt->aa[(ts->flags & MASK) != 0],因为我认为这更清楚和明确的。
    • 这很古怪,但它不是 C 最严重的滥用之一,也绝对不是 C++ 最严重的滥用之一。该语言只是为滥用代码而构建的。
    【解决方案4】:

    !EE == 0 相同,因此!!E(E == 0) == 0 相同。 !! 用于标准化布尔值。

    【讨论】:

      【解决方案5】:
      1. !!x 只是一个 !(!x)
      2. 如果NULL被定义为0,那么!!NULL == !!0 == !(!0) == !(1) == 0

      【讨论】:

        【解决方案6】:

        在 C99 中,您可以将其替换为

        #include <stdbool.h>
        
        
        pt->aa[(bool)(ts->flags & MASK)] = -val;
        

        当然,如果您的代码要移植到 C89,那么您最好执行 !!把戏或

        pt->aa[(ts->flags & MASK)!=0] = -val;
        

        pt->aa[(ts->flags & MASK)?1:0] = -val;
        

        生成的代码肯定是一样的。

        【讨论】:

          【解决方案7】:

          !!是在某些情况下使编译器安静的一种不错的方法,例如在具有多个表达式的条件中赋值,例如:

          int _blah = 100;
          int *blah;
          if ( _blah > 100 && !!(blah = &_blah) ) {
          // do stuff
          }
          

          我不建议这样做——警告通常是为了强制执行良好的编码习惯。

          【讨论】:

            猜你喜欢
            • 2015-06-25
            • 2013-07-31
            • 2011-10-24
            • 2011-08-06
            • 2011-06-11
            • 1970-01-01
            • 1970-01-01
            • 2013-02-12
            • 2011-06-10
            相关资源
            最近更新 更多