4.3 判等运算

1.为什么“=”要读成赋值

“=”需要被读成赋值的原因有两个,一是其本意就是赋予值,二是在C语言中真正具有“等于”含义的是另外一个运算符“==”。“==”是一种判等运算符(Equality Operators),这样的运算符一共有以下两种。

4.3 判等运算 - 图1

类似于关系运算,这两种判等运算的结果同样只有两种可能:int类型的0或1。两种判等运算运算符都是二元运算符。

优先级:皆为9。低于关系运算,高于赋值运算。

结合性:皆为从左到右。

类型转换规则:同前小节。

下面的代码是对程序代码4-4的一个改写。首先需要声明的是这不是最终的质量较好的代码(程序代码4-4也不是(4)),这个代码只是为了演示C的灵活性及的判等运算的使用,希望能达到拓展眼界、开阔思路的目的。

程序代码4-5

4.3 判等运算 - 图2

4.3 判等运算 - 图3

下面讨论使用判等运算符容易出现的一些问题。

2.2==2==2的真正含义

对于初学者来说,首当其冲最容易犯的一个错误是使用类似于:

4.3 判等运算 - 图4

这样的表达式表示3个数值相等关系的成立。在这里他们误以为这样的表达等同于数学中的:

4.3 判等运算 - 图5

而实际上,在C语言中,根据结合性,表达式2==2==2表达的含义是:

4.3 判等运算 - 图6

由于2==2的值为1,所以整个表达式的值为0。2==2==2表示的含义是表达式2==2的值是否和2相等。

3.1.1+2.2==3.3?

如果上机试一下,你可能会吃惊地发现:

4.3 判等运算 - 图7

这个语句的输出居然是0而不是1。这是一个典型的对判等运算的误用。

对浮点类型进行==、!=或>=、<=运算,在语法上是毫无疑问没有任何问题的。但是由于浮点类型小数部分的存储空间是确定且有限的,因此浮点类型通常只是不精确的近似值。对这样不精确的近似值进行==或!=运算在多数情况下是似是而非的。

再比如,对于:

double dl=1.00000000000000008,d2=1.00000000000000007;

你会发现dl==d2的值不是0而是1。

原因很简单,在dl内存和d2内存中真正存储的机器数,并非是数学上的1.00000000000000008和1.00000000000000007这两个值,而只是它们各自的近似值而已。所以dl==d2的值等于0或者等于1都是很有可能的,判断它们是否相等是没有意义的。

所以请记住:对浮点类型进行==或!=运算会显得很蠢。

4.如何杜绝“==”被误写

有太多的人常常误把==写成=了,甚至职业程序员中也有很多人犯这种低级错误。比如在代码中写:

4.3 判等运算 - 图8

这是个比较幸运的错误,因为能被编译器及时发现。而若是把:

4.3 判等运算 - 图9

写成了:

4.3 判等运算 - 图10

就没有那么幸运了。因为两者都是合法的表达式,只是表达的含义南辕北辙而已。为了避免这样的错误,有人发明了一个馊主意,他们像强迫症一样强迫自己习惯于在判断相等时把常量写在前而.就像下而这样:

4.3 判等运算 - 图11

他们指望一旦把==写成了=,表达式成了:

4.3 判等运算 - 图12

那么编译器就会发现这个错误。这个馊主意之所以馊,是因为并没有从根本上解决问题。比如一旦把:

4.3 判等运算 - 图13

写成了:

4.3 判等运算 - 图14

编译器是发现不了错误的。这个偏方之所以常常不灵,是因为没有找对病根对症下药。

这个错误的根源在于很多人由于数学上的积习,把“=”(赋值)读成了“等于”,因此杜绝这种低级错误的方法就在于把读“=”为“等于”的习惯改成读“=”为“赋值”。代码一旦能被正确地朗读(哪怕是默读),就至少能减少一半以上的低级错误。所以,从现在开始,把“=”读成“赋值”吧!只要养成习惯,你会受益终身。

多数人不会犯把“>=”写成“=>”或把“<=”写成“=<”这样的低级错误,但这样的错误的确有过,而且一直有。如果你的代码中出现了这样错误,请自己改正。

练习

已知a、b、c为整系数一元二次方程ax2+bx+c=0各项的系数。编程输入这3个系数,判断对应的一元二次方程是否有两个实根(显然,代码可以写得比前一小节简洁)。