为什么打开字符值不符合大小写0xC2?

Why doesn't switching on a char value reach case 0xC2?

本文关键字:大小写 0xC2 不符合 字符 为什么      更新时间:2024-04-28

在下面的代码中发现了一个错误,它解析C字符串并应该检测UTF8字符:

char* pTmp = ...;
...
switch (*pTmp)
{
case 'o':
{
...     // works fine
break;
}   
case 0xC2:
{
...     // never gets triggered
break;
}
}

但是,永远不会触发case 0xC2:

我的假设是0xC2被视为int,因此是 194,大于 127,char数据类型的最大值。所以-62 != 194

或者这里可能发生一些溢出或整数提升。

编写switch ((unsigned char)*pTmp)可以解决此问题。

但我想澄清一下这里到底发生了什么以及适用哪些规则。

我也愿意改变标题,只是没有更好的想法。

我在这里添加-Wall得到这个

warning: case label value exceeds maximum value for type [-Wswitch-outside-range]
14 |             case 0xC2:

所以是的,你的推理是正确的。

char有符号吗?

如果char具有与signed charunsinged char相同的范围,则它是特定于实现的。 在OP的情况下,char的范围为[-128 ...127],因此case 0xC2:永远不匹配。


但我想澄清一下这里到底发生了什么以及应用了哪些规则。

C标准库字符串函数有许多char *的参数,但这些库函数在内部就像指向unsigned char数据一样

对于此子句中的所有函数,每个字符都应解释为具有无符号字符类型(因此每个可能的对象表示形式都是有效的并且具有不同的值)。C17DR § 7.24.1 3

为了匹配这一点,OP的代码也应该这样做。 这样做还将允许*upTmp潜在地匹配0xC2

char* pTmp = ...;
unsigned char* upTmp = ( unsigned char*) pTmp;
switch (*upTmp)
case 0xC2:

替代使用十六进制常量0xC2,使用字符常量'xC2'以匹配char的范围。 @Eric Postpischil。

<小时 />

[迂腐]

"switch ((unsigned char)*pTmp)解决了问题。" - 它足够接近。

此"修复"适用于 2 的补码char,以及当定义的实现charunsigned char匹配时。

对于其余但不存在的情况,其中char是有符号而不是 2 的补码,修复是错误的,因为字符应该通过unsigned char *访问,否则使用错误的值。

switch (*(unsigned char *)pTmp)在所有情况下都能正常工作。