使用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(当天回来)。
- 主要用途
!!
是处理将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之后,使用!!
应付了这个弱点。 一些旧习惯需要很长时间才能死亡。
-
在早期的C ++中 ,没有
bool
types。 所以想要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)
-
当没有
(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)));