为啥 ~(true^true) 不正确?布尔运算符(否定)适用于“无符号字符”,但不适用于布尔值? (C++)

Posted

技术标签:

【中文标题】为啥 ~(true^true) 不正确?布尔运算符(否定)适用于“无符号字符”,但不适用于布尔值? (C++)【英文标题】:Why ~(true^true) is not true? Boolean operators (negation) works for `unsigned char`s, but not for bools? (C++)为什么 ~(true^true) 不正确?布尔运算符(否定)适用于“无符号字符”,但不适用于布尔值? (C++) 【发布时间】:2014-07-06 18:41:22 【问题描述】:

我听说除了 0 之外的“一切”通常都是真的。但是现在非常奇怪的事情发生在我身上......或者我只是认为我以正确的方式做这件事而我没有。以下是正在发生的事情:

当我想检查 a 是否等同于 b 时,我可以使用NOT(a XOR b)。例如,当我检查unsigned char 时,一切正常

unsigned char a = 5;
unsigned char b = 3;
unsigned char c = ~(a^b);

给我c == 249:

a 是:00000101,即 5。

b 为:00000011,即 3。

~(a^b) 为:11111001,即 249。

现在,让我们用bool's 试试这个。

cout << ~(true^true) << ~(true^false) << ~(false^true) << ~(false^false) << endl;
cout << ~(~(true^true)) << ~(~(true^false)) << ~(~(false^true)) << ~(~(false^false)) << endl;

if (~(true^true) == true)
    cout << "true";
else
    cout << "false";

这给了我控制台:

-1-2-2-1
0110
false

虽然我预计第一行是:

1001

问了一个朋友后,他建议我试试!而不是~,看看它是否能正常工作。而且(我认为)它现在可以正常工作。但我不明白为什么。布尔否定不应该对布尔值起作用吗?

【问题讨论】:

布尔否定确实适用于布尔值。 bitwise-NOT 没有。 A bool 不止一位。 ~ 翻转每一位。 真的,它只是不等于true 我们有多少种否定?我正在使用这个页面:cplusplus.com/doc/boolean,并且只提到了一个。 @Kusavil Kerrek 得到了一个很好的答案,你一定要读一读。 【参考方案1】:

~ 是按位非。

例如~0 对于 unsigned char 是 255,而 255 != true

【讨论】:

【参考方案2】:

逻辑否定和按位否定是有区别的。按位取反翻转变量中的位,逻辑取反翻转逻辑值,即真/假。例如,考虑数字 5,以二进制表示为 101。如果只翻转位 (~5),您将得到 11111010,这不是假的,因为在 c++ 中只有全零是假的。但是如果你计算 (!5) 你会得到全零,这将在一个条件内起作用。

【讨论】:

【参考方案3】:

您误解了算术转换。当您对某个整数类型的表达式e~e 时,该值首先被提升为至少int,对于e1 ^ e2 也是如此(对于任何算术表达式,就此而言)。所以true ^ true首先将其操作数提升为int,产生1 ^ 1,这确实是0,因此你最终得到~0,在你的平台上是-1

你可以通过将结果转换回bool来模糊地理解你的操作:

std::cout << static_cast<bool>(~(true ^ true))

在您的最后一个问题中,由于您有一个带有 == 运算符的表达式,其中两个操作数具有不同的类型,因此两个操作数都被提升为公共类型,这又是 int,而 -1 不同于1。同样,您可以先将两个操作数都转换为 bool 以获得所需的相等性。


元教训是,C++ 中作用于整数的内置运算符实际上只作用于int 和更宽的类型,但不能作用于任何较短的类型(boolcharshort)(类似的考虑适用于通过省略号传递整数)。虽然这有时可能会引起一些混乱,但我想它也稍微简化了语言规则。这都是 C++ 的 C 遗产的一部分。

【讨论】:

谢谢,我想我现在明白了:) “误解”?这是一个词,还是一个笑话从我头上飞过? @Quentin:不能两者兼而有之吗? :-)【参考方案4】:

我听说很多时候除了 0 之外的“一切”都是真的

它适用于例如 if 语句中的条件(这里和下面我引用 C++ 标准)

作为表达式的条件的值是 表达式,上下文转换为布尔语句,而不是 切换

例如,如果你写成

if (~(true^true) )
    cout << "true";
else
    cout << "false";

代替你的代码sn-p

if (~(true^true) == true)
    cout << "true";
else
    cout << "false";

或者当使用逻辑否定运算符!

9 逻辑否定运算符的操作数!是上下文的 转换为 bool(第 4 条);如果转换后,它的值为真 操作数为假,否则为假。结果的类型是bool

至于运营商== 那么

6 如果两个操作数都是算术或枚举类型,通常 对两个操作数执行算术转换;每个 如果指定的关系为真,则运算符应为真,并且 如果为假,则为假。

那是在

if (~(true^true) == true)

应用了通常的算术转换,即布尔值 true 被转换为整数值 1 并且它不等于左操作数的表达式,因为左操作数的内部二进制表示不同于 1,如您的第一个输出所示代码 sn-p..

【讨论】:

很好的答案,现在我很清楚到底发生了什么,谢谢!我在哪里可以找到您引用的标准?我在谷歌搜索时有点困惑。 @Kusavil 您可以在open-std.org/jtc1/sc22/wg21找到该标准的工作草案【参考方案5】:

仅考虑您的第一个示例,

~(true^true)

首先将^的操作数提升为int,这样就相当于

~(1^1)

然后将 1 与自身异或产生一个全零位模式,无论int 表示如何,它都表示值 0:

~0

这会将全零位模式中的每一位反转为 0,从而产生所有位为 1 的位模式,例如对于 32 位 int

int( 0xFFFFFFFF )

使用现在几乎通用的有符号整数的二进制补码形式表示,这就是值 -1。

因此你的输出是

-1

【讨论】:

以上是关于为啥 ~(true^true) 不正确?布尔运算符(否定)适用于“无符号字符”,但不适用于布尔值? (C++)的主要内容,如果未能解决你的问题,请参考以下文章

列表上的 Python 布尔运算 - 结果不一致

为啥析取赋值运算符 |= 不适用于布尔向量?

为啥 argparse 不能正确解析我的布尔标志? [复制]

那个布尔值不就是true ,false吗,怎么还又0和1了??不解

python-逻辑运算:not\and\or和布尔值:True\False

Python--Demo5--布尔类型相关操作