在C中if(function()== TRUE)的任何原因

Pet*_*man 9 c embedded microchip mplab

问题: 是否做了if(SomeFunction() == TRUE)而不是做if(SomeFunction())某些类型的编码错误?我试图了解这是否可以防止某些隐藏的地雷,或者是否是某人编写代码并且不太明白如何评估表达式的结果.我明白,如果做得对,这两件事情的评价都是一样的.就像if(value == 42)if(42 == value)评估相同 - 仍然,有些人更喜欢第二个版本,因为如果有人输错了==并且写入=而产生编译器错误.

背景: 我继承了一些4年或5年前由不在这里工作的人写的嵌入式软件.我正在进行一些重构以摆脱数百行函数和全局变量以及所有爵士乐,所以这个东西是可读的,我们可以继续保持它.代码是c用于pic微处理器.这可能相关也可能不相关.该代码有各种在它的尖叫奇怪的东西"不知道他们在做什么",但在这里我想了解是不是有一个很好的理由一个特定的模式(反模式?)

模式: 这里有很多if语句采用的形式

if(SomeFunction() == TRUE){
  . . .
}
Run Code Online (Sandbox Code Playgroud)

其中SomeFunction()定义为

BOOLEAN SomeFunction(void){
  . . .
  if(value == 3)
    return(FALSE);
  else
    return(TRUE);
}
Run Code Online (Sandbox Code Playgroud)

让我们忽略SomeFunction从if语句的主体返回TRUE或FALSE的奇怪方式,以及他们使'return'看起来像函数调用的奇怪方式.

这似乎打破了c认为'true'和'false'的正常值.就像,他们真的想确保返回的值等于任何被定义为TRUE的值.这几乎就像他们正在制作三种状态 - TRUE,FALSE和'其他'而且他们不希望在返回"其他东西"的情况下采用'if'语句.

我的直觉是,这是一种奇怪的反模式,但我想给这些家伙带来怀疑的好处.例如,我认识到if(31 == variable)看起来有点奇怪,但它是这样编写的,所以如果你输错了==你不会意外地将31分配给变量.如果这些人写了这个保护措施来防范类似的问题,或者这只是胡说八道.

附加信息

  • 当我写这个问题时,我的印象是stdbool不可用,但我现在看到它是由IDE提供的,只是在这个项目中没有使用过.这使我更倾向于"没有充分理由这样做".
  • 看起来BOOLEAN被定义为 typedef enum _BOOLEAN { FALSE = 0, TRUE } BOOLEAN;
  • 这里讨论的开发环境是MPLAB 8.6

Kei*_*son 17

有没有充分的理由去做if(SomeFunction() == true)而不是做if(SomeFunction())

没有.

如果SomeFunction()返回类型的结果_Bool,那么相等性比较应该是可靠的(假设结果的评估不涉及未定义的行为).但是使用TRUE而不是true和类型名称BOOLEAN而不是_Boolbool表示结果不是实际的_Bool(仅在C99或更高版本中可用),而是一些特殊的布尔类型 - 也许是别名int.

任何标量类型的值都可以用作if语句中的条件.如果该值等于零,则条件为假; 否则,条件为真.如果TRUE被定义为1,并且SomeFunction()返回3,那么测试将失败.

写作

if (SomeFunction()) { /* ... */ }
Run Code Online (Sandbox Code Playgroud)

更简单,更清晰,更有可能正常行事.

请注意,例如,声明的isdigit()等函数<ctype.h>不仅仅返回01; 如果参数是一个数字,isdigit()可以(并且确实)返回任何非零值.使用它的代码应该正确处理它 - 通过比较它的相等1,to true或to TRUE.

话虽如此,可能有一个合理的理由来比较某些东西的相等性TRUE- 如果重要的是结果是否等于TRUE或具有其他非零值.但在这种情况下,使用名称BOOLEANTRUE具有误导性.布尔类型的重点是值为true或false; 没有"可能",如果碰巧有不同的真理表示,你不应该关心你拥有哪一个.

我尝试遵循的准则是:

决不相等或不等的比较逻辑布尔值true或者false(或0,1,FALSE,TRUE).!如果要反转测试,只需使用操作员直接测试该值.("逻辑布尔"值既可以是类型_Bool,也可以用来区分真假,而无需额外的信息.如果_Bool不可用,则后者可能是必要的.)比较false可以是安全的,但没有理由这样做; 直接比较值仍然更清晰.

如果有人告诉你的话

if (SomeFunction() == true)
Run Code Online (Sandbox Code Playgroud)

比...更好

if (SomeFunction())
Run Code Online (Sandbox Code Playgroud)

只要问他们为什么

if ((SomeFunction() == true) == true)
Run Code Online (Sandbox Code Playgroud)

甚至不是更好.

另请参见comp.lang.c FAQ的第9节.它对C99前解决方案的重视可能有点过时,但它仍然有效.

更新:问题询问一个返回TRUE类型值的函数BOOLEAN,定义如下:

typedef enum { FALSE, TRUE } BOOLEAN;
Run Code Online (Sandbox Code Playgroud)

这样的定义是在1999年之前-C是有用的,但加入C99预定义的布尔类型_Bool和首标<stdbool.h>,它定义宏bool,falsetrue.我目前的建议:使用<stdbool.h>除非严重担心您的代码可能需要与不支持它的实现一起使用.如果这是一个问题,你可以使用

typedef enum { false, true } bool;
Run Code Online (Sandbox Code Playgroud)

要么

typedef int bool;
#define false 0
#define true 1
Run Code Online (Sandbox Code Playgroud)

(我更喜欢第一个.)这与C99定义不是100%兼容,但如果您明智地使用它,它将正常工作.

  • 基思,约翰 - 这是我在写这个问题时所相信的答案,我仍然相信这是正确的.我将保持这种开放一段时间,但以防一些经验丰富的嵌入式系统开发人员出现并说"实际上在pic32上使用编译器版本时......你需要注意......". (2认同)
  • @PeteBaughman:我建议最好的答案是在任何编译器上都有相同作用的答案,以及BOOLEAN,TRUE和FALSE的任何合理定义.这样做的一个论据是因为它在某些特定的编译器中以某种方式更好地工作在任何情况下都是一个坏论据.也就是说,我提倡在接受答案之前至少离开24小时,让所有时区都改变筹码.真的不急.而Keith看起来并不像他渴望代表! (2认同)