【问题标题】:Why doesn't switching on a char value reach case 0xC2?为什么打开 char 值没有达到 case 0xC2?
【发布时间】:2021-06-24 09:45:47
【问题描述】:

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

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

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

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

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

switch ((unsigned char)*pTmp) 解决了这个问题。

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

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

【问题讨论】:

  • case 0xC2: 正在与 int 值十进制 196 进行比较,但如果 charsigned 那么就像你说的那样,-62. 你可以验证 0xC2 是键入 intprintf("%zu\n", sizeof(0xC2));。另外:注意'o' 也是一个int 值。
  • 从评论中复制粘贴here: "C89 6.1.2.5 "共有三种字符类型,分别指定为 char 、signed char 和 unsigned char 。" C11 6.2.5p15 "这三种类型char、signed char 和 unsigned char 统称为字符类型。" 6.2.5fn45 "char 是与其他两种不同的类型,不兼容""
  • 我试图根据您对问题的表述方式给它一个更好的标题。
  • 你可以使用一个字符常量'\xc2',这样它就有一个字符值。

标签: c++ c switch-statement


【解决方案1】:

我在添加 -Wall here 时得到这个

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

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

【讨论】:

  • 这是相关信息,但您的结果是特定于实现的。
【解决方案2】:

char 签名了吗?

如果charsigned charunsinged char 具有相同的范围,则具体实现。在 OP 的情况下,char 的范围是 [-128 ... 127],因此 case 0xC2: 永远不会匹配。


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

C 标准库字符串函数有许多参数是char *,但这些库函数在内部的行为就好像它们指向unsigned 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) 解决了这个问题。” - 够近了。

此“修复”适用于签名为 char 的 2 的补码,以及当定义的实现 char 匹配 unsigned char 时。

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

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

【讨论】:

  • 如果他们出于某种原因使用char 而不是unsigned char,他们可以使用字符常量,如case '\xC2': 来获取相应的char 值。并且使用字符常量而不是整数常量可以更好地表达他们正在切换字符值。
猜你喜欢
  • 1970-01-01
  • 2018-03-23
  • 1970-01-01
  • 1970-01-01
  • 2014-04-07
  • 1970-01-01
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多