使用if(!!(expr))而不是if(expr)

在阅读德州仪器为其SensorTag提供的示例代码时,我遇到以下代码片段。

void SensorTagIO_processCharChangeEvt(uint8_t paramID) { ... if (!!(ioValue & IO_DATA_LED1)) { PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_ON); } else { PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF); } if (!!(ioValue & IO_DATA_LED2)) { PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_ON); } else { PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF); } if (!!((ioValue & IO_DATA_BUZZER))) { Clock_start(buzzClockHandle); } ... } 

声明就像这样(在同一个文件中)。

 #define IO_DATA_LED1 0x01 static uint8_t ioValue; 

if (!!(ioValue & IO_DATA_LED1))if (ioValue & IO_DATA_LED1)有优势吗?

两次应用逻辑not( ! )操作符的目的是将值标准化为0或1.在if语句的控制expression式中,这没有任何区别。 if语句只关心零或非零值,小!! 跳舞是完全没用的。

一些编码风格指南可能会要求这种舞蹈,这可能是你发布TI代码的原因。 我还没有看到这样做。

如果x是一个真值(一个非零数字或一个非空指针),则expression式!!x!(!x)意味着1,否则为0.它相当于x != 0 ,与C99几乎相同(_Bool)x但在C99之前或开发人员select不实施C99的编译器(如以MOS 6502为目标的cc65)中可用 。

作为一个整体的条件等同于以下内容:

 if (ioValue & IO_DATA_LED1) { /* what to do if the IO_DATA_LED1 bit is true */ } else { /* what to do if the IO_DATA_LED1 bit is false */ } 

在C中,它的意思是“如果这两个值的按位AND不为零,则执行该块”。

但是一些编码风格指南可能会禁止在if语句条件的顶层按位AND( & ),假设它是逻辑AND( && )的拼写错误。 它与使用= (赋值)而不是== (相等比较)的错误types相同,许多编译器都提供诊断。 GCC警告选项描述这样的诊断:

-Wlogical-op :警告expression式中逻辑运算符的可疑用法。 这包括在可能期望按位运算符的上下文中使用逻辑运算符。

-Wparentheses :如果在某些上下文中省略了括号,则会发出警告,例如在预期有真值的上下文中存在赋值

使用(a & B) != 0(_Bool)(a & B) (a & B) != 0 (_Bool)(a & B)!!(a & B)这样的释义与编译器和其他开发人员通信时,使用按位运算符是有意的。

另请参阅关于JavaScript中的JavaScript的相关答案。

在MSVC中,将一个整数转换为一个bool隐式地在一个if语句中可以产生一个警告。 这样做通过!! 才不是。 其他编译器可能存在类似的警告。

所以假设代码是在启用该警告的情况下编译的,并且决定将所有警告视为错误,请使用!! 是一个简短而便携的方式来说“是的,我希望这个整数是一个bool ”。

OP正在寻找一些旧的编码方式 – 这有点像BITD(当天回来)。

  1. 主要用途!! 是处理将if(expr)的expression式转换为int而不是对零进行testing的C实现。

考虑一下当expr被转换成int会发生什么,然后testing0。(因为C89,这是不符合的,因为testing应该是针对0的直接testing)

 int i; long li; double d; // no problems if (i & 5) ... if (d > 4.0) ... // problems if (li & 0x10000) ... (Hint: int is 16-bit) if (d) (d might have a value outside `int` range. // fix if (!!(li & 0x10000)) if (!!d) 

所以在C89之前的编译器和不合格的C89之后,使用!! 应付了这个弱点。 一些旧习惯需要很长时间才能死亡。

  1. 在早期的C ++中 ,没有booltypes。 所以想要testing信任的代码需要使用!! 成语

     class uint256; // Very wide integer uint256 x; // problem as (int)x may return just the lower bits of x if (x) // fix if (!!x) 
  2. 当没有(bool)运算符定义的时候,C ++今天会发生什么(我知道这是一个C问题),而不是使用的(int)运算符? 这会导致与#2相同的问题。 至于很多早期的C和C ++代码库保持同步,使用!!if (!!x)这样的结构具有相关性。


使用!! 今天起作用,但肯定不受欢迎,因为它解决了不再有任何显着频率发生的问题。

虽然沉默的编译器警告的比特明智&是最有可能的,这看起来也可能是重构的结果添加枚举的可读性来自:

 PIN_setOutputValue(int,int,bool); //function definition PIN_setOutputValue(hGpioPin, Board_LED1,!!(ioValue & IO_DATA_LED1)); PIN_setOutputValue(hGpioPin, Board_LED2,!!(ioValue & IO_DATA_LED2)); //note: the !! is necessary here in case sizeof ioValue > sizeof bool //otherwise it may only catch the 1st 8 LED statuses as @MM points out 

至:

 enum led_enum { Board_LED_OFF = false, Board_LED_ON = true }; PIN_setOutputValue(int,int,bool); //function definition //... PIN_setOutputValue(hGpioPin, Board_LED1,!!(ioValue & IO_DATA_LED1)?Board_LED_ON:Board_LED_OFF); PIN_setOutputValue(hGpioPin, Board_LED2,!!(ioValue & IO_DATA_LED2)?Board_LED_ON:Board_LED_OFF); 

由于超过了80个字符的限制,它被重构

 if (!!(ioValue & IO_DATA_LED1)) { PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_ON); } else { PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF); } if (!!(ioValue & IO_DATA_LED2)) { PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_ON); } else { PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF); } 

就个人而言,我更喜欢初始版本的可读性,但是当使用代码行作为度量标准时,这个版本是常见的(我很惊讶它没有为每个状态声明variables,分别设置每个状态然后使用它)。

这个“最佳实践”代码的下一个版本可能如下所示:

 bool boardled1State; bool boardled2State; //... boardled1State = !!(ioValue & IO_DATA_LED1); boardled2State = !!(ioValue & IO_DATA_LED2); //... if (boardled1State) { PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_ON); } else { PIN_setOutputValue(hGpioPin, Board_LED1, Board_LED_OFF); } if (boardled2State) { PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_ON); } else { PIN_setOutputValue(hGpioPin, Board_LED2, Board_LED_OFF); } //... and so on 

所有这一切都可以这样做:

 for (int i=0;i<numleds;i++) PIN_setOutputValue(hGpioPin, i ,!!(ioValue & (1<<i)));