UTF-8解码器在非ASCII字符上失败

UTF-8解码器在非ASCII字符上失败,c,C,注意:如果你关注了我最近的问题,你会发现它们都是关于我在C中的Unicode库练习——作为我在C中最初几个严肃的项目之一,我有很多问题,所以如果我问了太多关于一件事的问题,我很抱歉 我的库的一部分将UTF-8编码的char指针解码为原始无符号的代码点。但是,某些飞机无法正确解码。让我们看一下(相关)代码: 应打印: 10ffff 但它却打印出: fffffff4 ffffff8f ffffffbf ffffffbd 基本上是UTF-8的四个字节,前面加了ffffff 关于我的代码中的错误有什

注意:如果你关注了我最近的问题,你会发现它们都是关于我在C中的Unicode库练习——作为我在C中最初几个严肃的项目之一,我有很多问题,所以如果我问了太多关于一件事的问题,我很抱歉

我的库的一部分将UTF-8编码的
char
指针解码为原始
无符号的
代码点。但是,某些飞机无法正确解码。让我们看一下(相关)代码:

应打印:

10ffff
但它却打印出:

fffffff4 ffffff8f ffffffbf ffffffbd
基本上是UTF-8的四个字节,前面加了
ffffff


关于我的代码中的错误有什么指导吗?

允许对字符类型进行签名,然后将其转换为int,然后再转换为unsigned(这是直接转换为unsigned时隐式发生的情况),显示错误:

#include <stdio.h>

int main() {
  char c = '\xF4';
  int i = c;
  unsigned n = i;
  printf("%X\n", n);
  n = c;
  printf("%X\n", n);
  return 0;
}
#包括
int main(){
字符c='\xF4';
int i=c;
无符号n=i;
printf(“%X\n”,n);
n=c;
printf(“%X\n”,n);
返回0;
}
印刷品:

FFFFFFF4
FFFFF4


改为使用无符号字符。

允许对字符类型进行签名,然后将其转换为int,然后再转换为unsigned(这是直接转换为unsigned时隐式发生的情况),显示错误:

#include <stdio.h>

int main() {
  char c = '\xF4';
  int i = c;
  unsigned n = i;
  printf("%X\n", n);
  n = c;
  printf("%X\n", n);
  return 0;
}
#包括
int main(){
字符c='\xF4';
int i=c;
无符号n=i;
printf(“%X\n”,n);
n=c;
printf(“%X\n”,n);
返回0;
}
印刷品:

FFFFFFF4
FFFFF4


请改用无符号字符。

您可能忽略了一个事实,即
char
在您的平台上是一种有符号类型。始终使用:

  • 无符号字符
    如果要读取字节的实际值
  • 有符号字符
    如果将字节用作小的有符号整数
  • char
    用于抽象字符串,其中您不关心除0以外的值

顺便说一下,您的代码效率极低。与其对每个字符反复调用
realloc
,为什么不首先分配
sizeof(unsigned)*(strlen(old)+1)
,然后如果它太大,就减少最后的大小?当然,这只是众多低效率问题之一。

您可能忽略了一个事实,即
char
在您的平台上是一种签名类型。始终使用:

  • 无符号字符
    如果要读取字节的实际值
  • 有符号字符
    如果将字节用作小的有符号整数
  • char
    用于抽象字符串,其中您不关心除0以外的值

顺便说一下,您的代码效率极低。与其对每个字符反复调用
realloc
,为什么不首先分配
sizeof(unsigned)*(strlen(old)+1)
,然后如果它太大,就减少最后的大小?当然,这只是众多低效率问题之一。

非常感谢!将
ctou
的原型更改为这个固定的原型:
字符串ctou(unsigned char*old)非常感谢!将
ctou
的原型更改为这个固定的原型:
字符串ctou(unsigned char*old)顺便说一下,你的问题主题有误导性。这个问题与高平面(非BMP)字符无关;它发生在任何非ascii字符上。它实际上与UTF-8无关,而是与基本的C算法有关。你的UTF-8解码器也有一些错误,最糟糕的是你将解码无效的超长序列。我编辑了标题以提高相关性。如果您能告诉我您发现的其他一些错误,我将不胜感激。您正在阻止两字节超长,但不是更长的超长,例如0xE0,0x80,0xBC。您还允许0x10FFFF上的代码点、代理代码单元(不应出现在UTF-8中)以及>=0xC0字节后跟低位字节再后跟0x80-0xBF字节的序列。
while
循环使用不同的代码/检查每个长度情况可能更容易。但实际上,我会使用一些现有的库代码来解码UTF-8,而不是自己滚动它(因为错误解码/无效序列最终可能导致过滤器规避,从而产生安全后果)。另外,
upush
实现在病态上效率低下。哇,我的代码是一个非常糟糕的实现!;)--我最好开始做这些。但是,关于
upush
,如果
upush
本身只使用一个代码点,我如何提高效率?它做了它需要做的一切
realloc
然后将其插入。另外,我会使用另一个图书馆;我写这篇文章只是为了锻炼我的C语言技能。除了
upush
,你现在的代码相当快。。。但是,当您的实现错误时,很容易加快速度。:-)想一想,一旦你修复了“超长序列”和代理码点的解码,如何使其快速。还请记住,如果任何UTF-8解码器在每个字符上产生大量开销,那么它的速度都会很慢。高性能代码将在字符串上运行,但也将避免设置和退出开销,以防需要在短字符串/单个字符上调用。顺便说一句,您的问题主题具有误导性。这个问题与高平面(非BMP)字符无关;它发生在任何非ascii字符上。它实际上与UTF-8无关,而是与基本的C算法有关。你的UTF-8解码器也有一些错误,最糟糕的是你将解码无效的超长序列。我编辑了标题以提高相关性。如果您能告诉我您发现的其他一些错误,我将不胜感激。您正在阻止两字节超长,但不是更长的超长,例如0xE0,0x80,0xBC。您还允许0x10FFFF上的代码点、代理代码单元(不应出现在UTF-8中)以及>=0xC0字节后跟低位字节再后跟0x80-0xBF字节的序列。A
while
循环使用不同的c
#include <stdio.h>

int main() {
  char c = '\xF4';
  int i = c;
  unsigned n = i;
  printf("%X\n", n);
  n = c;
  printf("%X\n", n);
  return 0;
}