这个C/C++的if()语句会被评估为真吗?

5

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

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

我正在使用一个嵌入式系统的C编译器,它在对应位于“variable”中设置时将其评估为TRUE。我猜测编译器正在执行==两侧的TRUE/FALSE比较,而不是比较结果数字。换句话说,每次表达式(varable & 0x02)不为零(即TRUE)时,语句也将是TRUE,因为值1 也是 TRUE(不为零)。
我不知道标准是否清楚地定义了编译器在这种情况下应该如何行事。是否有任何基于标准(例如等)回答此问题的专家?
附:以上语句中,“variable”是无符号字符。

2
请问你能给这个编译器命名吗?我的一个朋友正在收集一些奇怪的编译器错误。 - blaze
1
你的真实代码中是否可能有双与符号(例如 "var && 0x02")?这可能会解释编译器将其评估为 true 的原因。 - tinman
@tinman 猜得不错,这将错误从编译器移动到程序代码中 :) - blaze
6个回答

11

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

更进一步地说,等号操作符被应用于两个整数值。重要的是两个操作数是否计算出相同的数字,而不是它们同时是“true”或“false”。

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

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

假设你所说的编译器确实存在这样的问题,那么它显然不符合标准。但是,它几乎肯定会正确处理if (variable & 0x02)。我的建议是修复代码,以便在更换编译器时不会悄悄崩溃。

最后,如果满足以下条件,情况就不同了:(1)代码是C ++而不是C; (2)variable是类的实例; 和(3)类重载了相关操作符。在这种情况下,行为取决于重载的操作符到底做了什么。


这是因为 0x02 在其位模式中只有一个位被设置。 - David Heffernan
4
由于存在重载运算符,在C++中情况并非如此。 - bdonlan
2
理想情况下,如果您想检查给定掩码中的所有位是否已设置,最好始终使用模式 if ((variable & CONST) == CONST) - tylerl
1
@aix 标记并询问关于 C 和 C++ 的信息 *耸肩* - bdonlan
我的建议是修复代码...代码是正确的。如果他真的有一个会出错的编译器(我非常怀疑),那么我的建议是更换编译器;一个会出错的编译器可能会出现很多其他问题,并且肯定是如此破碎以至于无法使用。 - James Kanze
显示剩余2条评论

6
在C++中,只有当variable是一个重载了operator&并且不符合正常按位与语义的类的实例时,这个条件才能评估为真值。
在C中,这个条件将始终为假。§6.5.10定义了按位与运算符的语义,它非常简单明了:
4. 二进制 & 运算符的结果是操作数的按位与(也就是说,结果中的每个位都设置了,当且仅当转换后的操作数中的对应位都设置了)。
很明显,结果不能为1,因为右侧操作数(即0x02)的转换值中没有设置1位。
自然地,如果程序的过去(或编译时)曾经调用了未定义行为,那么任何事情都可能发生。但除此之外,你的编译器是不兼容的。也就是说,它是有问题的。不幸的是,这在奇怪的嵌入式编译器上非常普遍。如果你幸运的话,甚至可以报告这个错误并得到修复。

4

我认为标准文件并没有针对这个非常特殊且不寻常的问题做出任何定义。正如aix所说,该语句永远不可能成立,因为(在二进制中):

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

(简化为8位类型)

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


1
谢谢您提供的可视化表示 :) - AntonioCS

1

对于C语言,答案是否定的。

C标准关于&(6.5.10)的解释如下:

二进制 & 运算符的结果是操作数的按位与(即,结果中的每个位仅在转换后的操作数的相应位均为 1 时才设置)。

由于在2中只有第1位被设置,表达式的值只能设置第1位。它只能取2和0这两个值,而2和0都不能等于1。

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


0
让我们考虑一下数字2的二进制值。
  02 = 0010 (say a 4 bit number)

二进制中1的值为

  01 = 0001 

数字2的最低有效位始终为0,也就是左侧最高位为0。因此,在与0进行&(与)操作时,永远不可能得出1,因此我们可以说它永远不可能等于1。

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

注意:&表示按位与操作。
   2 - 0010
   3 - 0011
       0010

因此,使用 xx & 2 的输出将为 0 或 2。


0

基本上,lint 就在这里。至少在我所知道的任何平台上,该条件将产生 false。看一下数字的位表示:x & 2 (0010) 将始终是零或 2 (0010),因此对于任何整数 x,它与 1 (0001) 不同。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接