比较总是以 char 和常量失败

Posted

技术标签:

【中文标题】比较总是以 char 和常量失败【英文标题】:Comparison always fails with char and constant 【发布时间】:2016-03-28 19:54:57 【问题描述】:

我试图比较一个字符串的第一个字符和一个十六进制常量来确定数据的类型。但每次都失败。谁能解释为什么下面的比较总是失败。

char charray[] = 0xAA, 0x00, 0x02;
char ch = charray[0];
if (0xAA == ch)

    printf("Equal\n");

【问题讨论】:

【参考方案1】:

问题出在这里:

char charray[] = 0xAA, 0x00, 0x02;

char 类型具有实现定义的符号,这意味着在某些系统上它将等同于signed charsigned char 最多只能存储 0x7F 的值,并且 MSB 将被视为符号位。这就是在您的情况下发生的情况,0xAA 被转换为 -86 的有符号值(它得到的值是由实现定义的,我假设是二进制补码)。

符号随后保留在表达式 0xAA == ch 中,因为 ch 随后被提升为类型 int 并且符号被保留。这意味着您实际上会比较 0xAA == -86 这是错误的。

为避免此类错误,在进行任何形式的字节级算术时,请始终使用uint8_t

【讨论】:

【参考方案2】:
if (0xAA == ch)

假设charsigned charchar 的行为为signed charunsigned char 在C 中取决于实现),char== 表达式中提升为int您实际比较的 32 位系统:

if (0xAA == 0xFFFFFFAA)

这是错误的。

防止符号扩展的一种方法是将右操作数强制转换为unsigned char

if (0xAA == (unsigned char) ch)

但最好在声明数组时使用unsigned char

【讨论】:

不,他实际上是在比较0xAA == -86。不一定与0xAA == 0xFFFFFFAA 相同,具体取决于隐式促销在特定系统上的结果。 @Lundin 如果你想挑剔的话,他实际上是在比较 0xAA == (signed char) 0xAA 这甚至是不同的,因为转换是实现定义的。 我的意思是:只要左操作数(int 字面量)是int,那么 char 只会经过整数提升(整数提升规则)并保持有符号。但是如果文字是无符号类型,也会有平衡(通常的算术转换),并且正确的操作数也会被转换为无符号类型。在这种情况下,您实际上最终会等于0xFFFFFFAAu。但这在这个特定的例子中不会发生。 @Lundin 如果左操作数是unsigned int,那么ch 在最终转换为unsigned int 之前仍将提升为int【参考方案3】:

0xAA 是一个 int 文字。 char 可以在您的系统上签名或未签名。 C 标准允许两者之一。

0xAA == ch 中,ch 被提升为 int 类型,比较结果为 0。

【讨论】:

以上是关于比较总是以 char 和常量失败的主要内容,如果未能解决你的问题,请参考以下文章

字符串比较字符指针和字符串的存储位置

char *p 与char p[] 比较

char *p 与char p[] 比较

两个varchars之间的比较

字符串的常量池和字符串的比较相关方法

Oracle 10 和 JDBC:如何让 CHAR 在比较时忽略尾随空格?