使用 if (!!(expr)) 而不是 if (expr)
Using if (!!(expr)) instead of if (expr)
在阅读德州仪器 (Texas Instruments) 为其 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)
有什么优势吗?
两次应用逻辑非 (!
) 运算符的目的是将值规范化为 0 或 1。在 if 语句的控制表达式中,这没有任何区别。 if 语句只关心值是零还是非零,!!
小舞完全没用。
一些编码风格指南可能会强制要求这种舞蹈,这可能是您发布的 TI 代码这样做的原因。不过我还没有看到这样做。
表达式!!x
或!(!x)
表示如果x
为真值(非零数或非空指针)则为1,否则为0。等价于x != 0
,它与 C99 (_Bool)x
几乎相同,但在早于 C99 的编译器或其开发人员选择不实现 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语言中,表示"if the bitwise AND of those two values is nonzero, execute the block."
但是某些编码风格指南可能会禁止在 if
语句条件的顶层使用按位 AND (&
),假设它是逻辑 AND (&&
).它与使用 =
(赋值)而不是 ==
(相等比较)的错误相同 class,许多编译器为此提供了诊断。 GCC Warning Options 描述了这样的诊断:
-Wlogical-op
: Warn about suspicious uses of logical operators in expressions. This includes using logical operators in contexts where a bit-wise operator is likely to be expected.
-Wparentheses
: Warn if parentheses are omitted in certain contexts, such as when there is an assignment in a context where a truth value is expected
使用诸如 (a & B) != 0
、(_Bool)(a & B)
或 !!(a & B)
之类的释义是在向编译器和其他开发人员表明使用按位运算符是有意的。
另请参阅有关 !!x
in JavaScript 的相关回答。
在 MSVC 中,在 if
语句中将整数隐式转换为 bool
会生成警告。通过 !!
这样做不会。其他编译器中可能存在类似的警告。
所以假设代码是在启用该警告的情况下编译的,并且决定将所有警告视为错误,使用 !!
是一种简短且可移植的方式来表示 "yes, I want this integer to be a bool
".
OP is looking at some old coding idiom - which made some sense BITD (back-in-the day).
!!
的主要用途是处理将 if(expr)
中的表达式转换为 int
的 C 实现,而不是针对零进行测试。
考虑当 expr
转换为 int
然后针对 0 进行测试时会发生什么。(从 C89 开始,这是不符合要求的,因为测试应该是针对 0 的直接测试)
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 及更高版本上,使用 !!
来解决这个弱点。有些旧习惯需要很长时间才能改掉。
在early C++中,没有bool
类型。因此,想要测试可信度的代码需要使用 !!
惯用法
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 @M.M 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);
}
就我个人而言,为了可读性,我更喜欢初始版本,但是当代码行用作度量时,这个版本很常见(我很惊讶它没有为每个状态声明变量,单独设置每个状态并且然后使用那个)。
此 "Best Practice" 代码的下一个版本可能如下所示:
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)));
在阅读德州仪器 (Texas Instruments) 为其 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)
有什么优势吗?
两次应用逻辑非 (!
) 运算符的目的是将值规范化为 0 或 1。在 if 语句的控制表达式中,这没有任何区别。 if 语句只关心值是零还是非零,!!
小舞完全没用。
一些编码风格指南可能会强制要求这种舞蹈,这可能是您发布的 TI 代码这样做的原因。不过我还没有看到这样做。
表达式!!x
或!(!x)
表示如果x
为真值(非零数或非空指针)则为1,否则为0。等价于x != 0
,它与 C99 (_Bool)x
几乎相同,但在早于 C99 的编译器或其开发人员选择不实现 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语言中,表示"if the bitwise AND of those two values is nonzero, execute the block."
但是某些编码风格指南可能会禁止在 if
语句条件的顶层使用按位 AND (&
),假设它是逻辑 AND (&&
).它与使用 =
(赋值)而不是 ==
(相等比较)的错误相同 class,许多编译器为此提供了诊断。 GCC Warning Options 描述了这样的诊断:
-Wlogical-op
: Warn about suspicious uses of logical operators in expressions. This includes using logical operators in contexts where a bit-wise operator is likely to be expected.
-Wparentheses
: Warn if parentheses are omitted in certain contexts, such as when there is an assignment in a context where a truth value is expected
使用诸如 (a & B) != 0
、(_Bool)(a & B)
或 !!(a & B)
之类的释义是在向编译器和其他开发人员表明使用按位运算符是有意的。
另请参阅有关 !!x
in JavaScript 的相关回答。
在 MSVC 中,在 if
语句中将整数隐式转换为 bool
会生成警告。通过 !!
这样做不会。其他编译器中可能存在类似的警告。
所以假设代码是在启用该警告的情况下编译的,并且决定将所有警告视为错误,使用 !!
是一种简短且可移植的方式来表示 "yes, I want this integer to be a bool
".
OP is looking at some old coding idiom - which made some sense BITD (back-in-the day).
!!
的主要用途是处理将if(expr)
中的表达式转换为int
的 C 实现,而不是针对零进行测试。
考虑当 expr
转换为 int
然后针对 0 进行测试时会发生什么。(从 C89 开始,这是不符合要求的,因为测试应该是针对 0 的直接测试)
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 及更高版本上,使用 !!
来解决这个弱点。有些旧习惯需要很长时间才能改掉。
在early C++中,没有
bool
类型。因此,想要测试可信度的代码需要使用!!
惯用法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 @M.M 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);
}
就我个人而言,为了可读性,我更喜欢初始版本,但是当代码行用作度量时,这个版本很常见(我很惊讶它没有为每个状态声明变量,单独设置每个状态并且然后使用那个)。
此 "Best Practice" 代码的下一个版本可能如下所示:
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)));