Q#defineTRUE定义为 1 是否危险,因为在 C 语言中任何非零值都被认为是“真”?如果内置的逻辑运算符或关系运算符“返回”的值不是 1 怎么办?
A在 C 语言中,任何非零值都被认为是真,但这只适用于“输入时”,也就是说,在期望布尔值的地方。当布尔值由内置运算符(如==, !=,而<=)生成时,它保证是 1 或 0。因此,测试
if((a == b) == TRUE)将按预期工作(只要TRUE为 1),但这显然是愚蠢的。事实上,显式测试TRUE和FALSE通常是不合适的。特别是,与内置运算符不同,一些库函数(尤其是isupper, isalpha等)在成功时返回一个非零值,该值*不*一定为 1,因此将其返回值与单个值(如TRUE)进行比较是相当冒险的,并且很可能不起作用。
(此外,如果你认为
if((a == b) == TRUE)比
if(a == b)是一个改进,为什么不就此止步呢?为什么不使用
if(((a == b) == TRUE) == TRUE)甚至
if((((a == b) == TRUE) == TRUE) == TRUE)刘易斯·卡罗尔的文章《乌龟对阿喀琉斯说》。)
鉴于
if(a == b)是一个完全合法的条件,那么
#include <ctype.h> ... if(isupper(c)) { ... }也是如此,因为isupper已知返回零/非零分别代表假/真。同样,在像
int is_vegetable; /* really a bool */ ... if(is_vegetable) { ... }或
extern int fileexists(char *); /* returns true/false */ ... if(fileexists(outfile)) { ... }这样的代码中,不应有任何顾虑,只要is_vegetable和fileexists()是“概念上的布尔类型”。像
if(is_vegetable == TRUE) or if(fileexists(outfile) == YES)这样的替代方案并没有真正的改进。(可以将它们视为“更安全”或“更好的风格”,但也可以将它们视为冒险或糟糕的风格。它们读起来肯定不那么流畅。参见问题17.10。)
一个好的经验法则是,仅将TRUE和FALSE(或类似)用于赋值给布尔变量或函数参数,或作为布尔函数的返回值,但切勿用于比较。
另请参阅问题5.3。
参考:K&R1 第 2.6 节第 39 页,第 2.7 节第 41 页
K&R2 第 2.6 节第 42 页,第 2.7 节第 44 页,第 A7.4.7 节第 204 页,第 A7.9 节第 206 页
ISO 第 6.3.3.3 节,第 6.3.8 节,第 6.3.9 节,第 6.3.13 节,第 6.3.14 节,第 6.3.15 节,第 6.6.4.1 节,第 6.6.5 节
H&S 第 7.5.4 节第 196-7 页,第 7.6.4 节第 207-8 页,第 7.6.5 节第 208-9 页,第 7.7 节第 217-8 页,第 7.8 节第 218-9 页,第 8.5 节第 238-9 页,第 8.6 节第 241-4 页
刘易斯·卡罗尔,《乌龟对阿喀琉斯说》