为啥 ~(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 没有。 Abool
不止一位。 ~ 翻转每一位。
它是真的,它只是不等于到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
和更宽的类型,但不能作用于任何较短的类型(bool
、char
、short
)(类似的考虑适用于通过省略号传递整数)。虽然这有时可能会引起一些混乱,但我想它也稍微简化了语言规则。这都是 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++)的主要内容,如果未能解决你的问题,请参考以下文章
为啥 argparse 不能正确解析我的布尔标志? [复制]
那个布尔值不就是true ,false吗,怎么还又0和1了??不解