【问题标题】:Can this C/C++ if() statement ever evaluate to TRUE?这个 C/C++ if() 语句可以评估为 TRUE 吗?
【发布时间】:2011-12-26 19:53:47
【问题描述】:

根据PC-lint,以下语句永远不会是TRUE

if((variable & 0x02) == 1)

我正在使用用于嵌入式系统的 C 编译器,只要设置了 variable 中的相应位,就会将其评估为 TRUE。我猜编译器正在对== 的两侧进行TRUE/FALSE 比较,而不是比较结果数字。换句话说,每当表达式(varable & 0x02) 不为零(即TRUE)时,语句也将为TRUE,因为值1 is also TRUE(不为零)。

我不知道C/C++ 标准是否明确定义了编译器在这种情况下的行为方式。是否有任何C/C++ 专家可以根据标准(例如C90, C99, 等)的内容回答这个问题?

P.S.:在上面的语句中,“变量”是一个无符号字符。

【问题讨论】:

  • 能否请您命名这个编译器?我的一个朋友收集了一些奇怪的编译器错误。
  • 你的真实代码是否有可能有一个双&符号(例如“var && 0x02”)?这可以解释编译器将其评估为真的。
  • @tinman 猜得好,这会将错误从编译器转移到程序代码:)

标签: c++ c if-statement conditional-statements


【解决方案1】:

PC-lint 是对的。假设var 是一个整数变量,表达式var & 0x02 可以计算为两个值:02。它永远不会等于1,这是if 语句正在测试的内容。

为了对此进行扩展,将相等运算符应用于两个整数值。重要的是两个操作数的计算结果是否相同,而不是它们同时是“真”还是“假”。

要测试是否设置了第 1 位,可以使用:

if (variable & 0x02) {
  ...
}

鉴于您的编译器按照您所说的方式运行,它显然是不合规的。但是,它几乎肯定会正确处理if (variable & 0x02)。我的建议是修复代码,以便在您更改编译器时不会静默中断。

最后,如果出现以下情况,情况会有所不同: (1) 代码是 C++ 而不是 C; (2) variable 是一个类的实例; (3) 类重载有问题的运算符。在这种情况下,行为取决于重载运算符的实际操作。

【讨论】:

  • 这是因为0x02 在其位模式中只设置了一个位。
  • 由于存在重载运算符,这在 C++ 中不是这种情况。
  • 理想情况下,如果要检查是否设置了给定掩码中的所有位,则应始终使用模式 if ((variable & CONST) == CONST)
  • 这肯定是一种查看方式。但我的问题是“标准对此有何评论?”。
  • @aix 他标记并询问有关 C 和 C++ *shrug* 的信息
【解决方案2】:

在 C++ 中,如果(且仅当)variable 是具有不符合正常按位与语义的重载 operator& 的类的实例,则 this 可以评估为真值。

在 C 中,这个条件总是为假的。 §6.5.10 定义了按位与运算符的语义,非常简单明了:

 4. 二元 & 运算符的结果是操作数的按位与(即 当且仅当转换的操作数中的每个相应位都被设置时,结果才被设置 设置)。

很明显,结果不能为1,因为右侧操作数(即0x02)的转换值中没有设置1位。

当然,如果在程序过去的某个时间点(或在编译时!)调用了未定义的行为,那么任何事情都可能发生。但是,除非有这种可能性,否则您的编译器是不兼容的。也就是说,坏掉了。不幸的是,这非常在奇怪的嵌入式编译器上很常见。如果幸运的话,您甚至可以报告错误并修复它。

【讨论】:

    【解决方案3】:

    我认为该标准没有对这个非常具体和不寻常的问题做出任何定义。正如 aix 所说,该陈述永远不会正确,因为(二进制):

    XXXX XXXX -> variable
    0000 0010 -> 0x02
    --------- AND
    0000 00X0 -> result
    

    (简化为 8 位类型)

    因此,您唯一的结果可以是 0000 0010(即 2)或 0000 0000(即 0)。

    【讨论】:

    • 感谢您的视觉表现 :)
    【解决方案4】:

    基本上,lint 就在这里。至少在我知道的任何平台上,条件都会产生错误。查看数字的位表示:x & 2 (0010) 将始终为零或 2 (0010),因此对于任何整数 x 都不同于 1 (0001)。

    【讨论】:

      【解决方案5】:

      对于 C,答案是否定的。

      C standard 表示 & (6.5.10):

      二元 & 运算符的结果是操作数的按位与(即 当且仅当转换的操作数中的每个相应位都被设置时,结果才被设置 设置)。

      由于在2中只设置了位1,所以表达式的值只能设置位1。它不能取2和0以外的值。2和0都不能比较等于1。

      整数的位表示在 6.2.6.2 中定义(用于通常方式的非负值)。

      【讨论】:

        【解决方案6】:

        让我们考虑 2 的二进制值

          02 = 0010 (say a 4 bit number)
        

        而1的二进制值是

          01 = 0001 
        

        2的最低位总是0,即最左边的位是0。所以
        与 0 的 & (and) 运算永远不会给出 1,因此我们可以说它永远不会等于 1

              0 0 =>    0
              0 1 =>    0
              1 1 =>    1 
        

        注意:& 表示位和运算

           2 - 0010
           3 - 0011
               0010
        

        所以 xx & 2 的输出将是 0 或 2。

        【讨论】:

          猜你喜欢
          • 2013-08-27
          • 2011-12-22
          • 2010-12-01
          • 2016-05-17
          • 1970-01-01
          • 1970-01-01
          • 2015-04-16
          • 2013-06-01
          • 2017-04-08
          相关资源
          最近更新 更多