【发布时间】:2011-04-16 18:47:03
【问题描述】:
我的 Unicode 库中有一部分将 UTF-16 解码为原始 Unicode 代码点。但是,它没有按预期工作。
这是代码的相关部分(省略 UTF-8 和字符串操作):
typedef struct string {
unsigned long length;
unsigned *data;
} string;
string *upush(string *s, unsigned c) {
if (!s->length) s->data = (unsigned *) malloc((s->length = 1) * sizeof(unsigned));
else s->data = (unsigned *) realloc(s->data, ++s->length * sizeof(unsigned));
s->data[s->length - 1] = c;
return s;
}
typedef struct string16 {
unsigned long length;
unsigned short *data;
} string16;
string u16tou(string16 old) {
unsigned long i, cur = 0, need = 0;
string new;
new.length = 0;
for (i = 0; i < old.length; i++)
if (old.data[i] < 0xd800 || old.data[i] > 0xdfff) upush(&new, old.data[i]);
else
if (old.data[i] > 0xdbff && !need) {
cur = 0; continue;
} else if (old.data[i] < 0xdc00) {
need = 1;
cur = (old.data[i] & 0x3ff) << 10;
printf("cur 1: %lx\n", cur);
} else if (old.data[i] > 0xdbff) {
cur |= old.data[i] & 0x3ff;
upush(&new, cur);
printf("cur 2: %lx\n", cur);
cur = need = 0;
}
return new;
}
它是如何工作的?
string 是一个保存 32 位值的结构体,string16 用于 UTF-16 等 16 位值。 upush 所做的只是将完整的 Unicode 代码点添加到 string,并根据需要重新分配内存。
u16tou 是我关注的部分。它循环通过string16,正常传递非代理值,并将代理对转换为完整的代码点。错误放置的代理将被忽略。
一对中的第一个代理将其最低 10 位向左移动 10 位,从而形成最终代码点的高 10 位。另一个代理将其最低 10 位添加到最后,然后将其附加到字符串。
问题所在?
让我们试试最高的代码点,好吗?
U+10FFFD,最后一个有效的 Unicode 代码点,在 UTF-16 中编码为 0xDBFF 0xDFFD。让我们尝试解码。
string16 b;
b.length = 2;
b.data = (unsigned short *) malloc(2 * sizeof(unsigned short));
b.data[0] = 0xdbff;
b.data[1] = 0xdffd;
string a = u16tou(b);
puts(utoc(a));
使用utoc(未显示;我知道它正在工作(见下文))函数将其转换回UTF-8 char * 进行打印,我可以在终端中看到我收到@987654333 @,结果不是U+10FFFD。
在计算器中
在 gcalctool 中手动进行所有转换会导致相同的错误答案。所以我的语法本身没有错,但算法错了。虽然算法对我来说似乎是正确的,但结果却是错误的答案。
我做错了什么?
【问题讨论】: