繁体   English   中英

在使用多个逻辑NOT运算符评估条件时出现混淆

[英]Confusion while evaluating conditions with more than one logical NOT operator

当代码包含多个NOT运算符时,我很困惑:

if (!x != !0)
  ;

或类似的。 我可以把它读作:如果不是x不等于非零,但在我看来,我对它的实际含义完全感到困惑。

你对此有什么建议吗? 即如何理解这样的代码,从哪里开始阅读等。

另一个例子:

if(!x == !1)

如果您不确定,可以使用真值表 例如

x | 0 | x!=0 | !x | !0 | !x != !0
0 | 0 |  0   |  1 |  1 |    0
1 | 0 |  1   |  0 |  1 |    1

如果有许多&&和||有问题,请使用de Morgan定律

为了使事情更简单,评估operator! 首先阅读L-> R.

要记住的事情:

!0 = 1 // true
!1 = 0 // false

所以你的病情可以简化为:

if (!x != true)  // !0
if (!x == false) // !1

现在,反转时的任何非零值都将zero

int x = 10;
!x // zero

倒立时true

int x = 0;
!x // one

在C或C ++中, true1false0

我假设问题是关于C,因此我将在C中给出答案。

你需要知道优先规则 - ! 绑定强于!= 因此,可以使用括号将表达式澄清为(!x) != (!0) 现在,接下来要知道的是什么! 将做-其结果将是0 ,如果操作数是非零1 ,如果它是零。 因此, !0可以恒定折叠为1

现在我们有(!x) != 1 由于!x为1 当且仅当 x是零,这整个表达式的结果将是1 IFF x是非零的,否则为0。

因此,我们可以将这种表达式简化为更惯用的双重否定: !!x 但是, if子句本身测试表达式是否为非零,因此整个if语句可以更改为if (x) ; (因为表达式只保护空语句,所以可以完全省略)

当我开始在PowerBuilder上开发时,我也遇到了simalar语法问题,然后我意识到我只需要将它想象为嵌套,如果检查错误。 例如!x变为if(x)= false,因此当x为假或零时,它更清楚为真。 在C 0是假的,任何不为零都是真的。

在同样的逻辑中!1总是假的!0总是如此,尽管我看不出以这种令人困惑的方式输入它的原因,也许你正在看的代码是从一种自动发生器/转换器出来的。

首先看一下运算符优先级 你会看到那些逻辑运算符 ! 优先于关系运算符,!=

其次,是什么!0 - 这可疑地听起来像是从intbool的隐式转换 - 否则!0根本没有任何意义。

在您的示例中,您需要首先评估逻辑运算符(即!x!0 ),然后检查它们是否不相等!= 也就是说,这种代码非常糟糕,因为它很难阅读 - 如果可能的话,避免编写这样的代码(考虑重构它 - 在单元测试中覆盖 - 如果你在“疯狂”中遇到它)

这种代码旨在欺骗你。 你的大脑难以处理双重否定或三重否定(而你不是唯一的否定)。

您需要知道什么是优先级规则,并应用它:

(!x == !1)等于((!x) == (!1))

如果您在代码审查期间看到此类代码,则应明确突出显示该代码,并要求进行更新。

请注意,在C ++中你也可以使用not而不是! 它可以使事情更容易理解:

(!x == !1)等于((not x) == (not 1))

在C和C ++中,值为零被视为“假”,非零值被视为“真”。 但它偶尔会引起混淆,偶尔会引起一些小问题,即使两种不同的价值观都不同,也可以认为是真实的。

例如,假设你有一个函数is_rich()告诉你一个人是否富裕。 假设你编写了这样的代码:

int harry_is_rich = is_rich("Harry");
int sally_is_rich = is_rich("Sally");

现在变量harry_is_rich根据Harry是贫穷还是富有而为零或非零,并且根据Sally是贫穷还是富有, sally_is_rich为零或非零。

现在假设你有兴趣了解Harry和Sally是否富有,或者两者都是穷人。 你的第一个想法可能是

if(harry_is_rich == sally_is_rich)

可是等等。 因为在C中任何非零值都被认为是“真”,如果出于某种原因,当哈利富有时, is_rich()函数返回2,当莎莉富有时返回3,该怎么办? 本身就不是一个错误 - 如果这个人有钱,那么is_rich()函数完全符合它返回非零的规范 - 但它会导致你无法写的情况

if(harry_is_rich == sally_is_rich)

(当然,你可以它,但是像任何错误的代码一样,它可能无法正常工作。)

那你能做什么呢? 好吧,一种可能性是写作

if(!harry_is_rich == !sally_is_rich)

你可以把它读成“如果不是哈利有钱的情况与萨莉富裕的情况不一样”。 而且,虽然它显然有点扭曲,但你可以说服自己,它“意味着”同样的事情。

而且,虽然它有点令人困惑,但它具有工作的优势。 它起作用是因为C和C ++中的真/假值的另一个令人困惑的方面。

虽然,正如我所说,零被认为是假的,任何非零值都被认为是真的,内置运算符产生真/假值 - 像&&|| ,和! - 实际上保证准确地给你0或1.(也就是说,内置函数在这方面与is_rich()类的函数明显不同。通常, is_rich()可能返回2或3,或者37为“true”。但是&&||!保证返回1表示true,0表示false表示。)

所以,当你说!harry_is_rich ,如果Harry有钱,你会得到0,如果Harry不富有,你会得到1。 当你说!sally_is_rich ,如果莎莉有钱,你将获得0,如果莎莉不富有,你将获得1。 如果你说

if(!harry_is_rich == !sally_is_rich)

无论is_rich()选择返回什么值,你都会正确地发现Harry和Sally是富人还是穷人。

还有一件事。 在所有这些中,我一直在考虑整数(或其他可能有很多值的类型)。 但是C和C ++都有bool类型,更简洁地表示真/假值。 对于bool类型, 正好有两个值, truefalse (表示为1和0)。 所以对于bool类型,你不能拥有除1以外的任何值的真值。因此,如果is_rich()函数被声明为返回bool ,或者如果你将变量声明为bool ,那么这将是另一种强制值为0/1,在这种情况下为条件

if(harry_is_rich == sally_is_rich)

会工作得很好。 (此外,当我说像&&||!这样的运算符保证正好返回1或0时,这基本上是因为这些运算符不“返回”任意整数,而是“返回”bool。)

另见C FAQ列表问题9.2

(噢,等等。 还有一两件事 。“富”相对的是不一定是“穷人”,当然:-))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM