使用“==”运算符将一个char与0x80进行比较,结果总是为false?

4
char byte = 0x80
if(byte == 0x80)
{
    cout << "This message never gets printed!";
}

十六进制值0x80在二进制中等同于1000 0000,明显适合一个字节。
然而,在带有条件的那一行,编译器会对我发出警告:
warning: comparison is always false due to limited range of data type

在这种情况下,条件为false的原因是什么? 0x80是否会被扩展为类似于0x80000000的内容?
是否可以使用==运算符检查char是否等于0x80

2
char 可以是有符号的或无符号的。 - chris
是的。但即使 0x80 解析为负数,我们只是比较 char 的内容是否等于字面量吗?如果不是,请解释一下! :) - Cory Klein
4
0x80 是一个整数(int)。 - Jesse Good
这个之前也困扰过我。非常烦人。 - Neil Kirk
更令人烦恼的是,这种比较在某些架构上会返回true,在其他架构上则会返回false。因此,当编译到不同平台时,原本正常工作的代码会突然出现问题。而在我的情况下,编译器没有发出任何警告,就像你所得到的那样。 - Michael
2个回答

10
问题在于,在C和C++标准中,字符(char)的定义可以是有符号或无符号的,并且一个字符(char)必须至少有8位。所涉及的架构和编译器似乎使用带符号的8位字符(char)值。
这意味着,任何具有最高位(第7位)的值都将是负值。因此,作为字符(char)的0x80变成了-128十进制数。
常量0x80不是字符(char)值,而是int值。
因此,当您将-128与0x80(128)进行比较时,它们不同,并且永远不会相同,编译器会发现这一点并发出警告。
有各种方法可以解决这个问题,以下是几种可能的情况:
首先,我们可以将任何一个值转换为另一个类型:
if (((int)byte) & 0xff == 0x80)

或者

if (byte == (char)0x80) 

或者,我们可以将常量变成char值,而不是int值。

if (byte == '\200')     // Octal 200 = 0x80. 

或者

if (byte == '\x80')

或者,使用 unsigned char byte = 0x80; - 指定它是无符号字符将确保它不会“翻转为负数”。


为了完整起见,我要补充一下,在clang和gcc下,你也可以使用-funsigned-char编译,这将强制所有的char都是无符号的。 - wds

0

signed char类型可以包含值0x7f-0x80,总共256个值。而unsigned char类型可以包含值0x80,因为最大值是0xff。看起来你正在使用的char类型实现是一个signed char类型。

0x80赋值给signed char会强制发生值溢出,使值变为-0x80。由于最高位被用作符号位,所以signed char类型无法将0x80表示为系统中的值,因为它总是被解释为-0x80

如果您使用按位与运算符:byte & 0x80,则可以成功进行比较。请注意,此操作的结果不意味着双向相等性,仅表示最高位是否设置。


1
char类型可以是有符号的或无符号的,因此你的第一句话并不总是正确的。 - chris
2
带有&的测试不等同于相等。 - David Rodríguez - dribeas
@DavidRodríguez-dribeas 正确。即使 byte 不包含 0x80byte & 0x80 也可能为真。例如,0x80&0x81 将评估为真。 - Cory Klein
它会溢出,但值将是-128,而不是-1! - Mats Petersson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接