注意:如果你已经按照我最近的问题,你会发现它们都是关于我在C中使用我的Unicode库练习 - 作为我在C中的几个重要项目之一,我遇到了很多问题,如果我对一件事问了太多问题,我很抱歉。
我的库的一部分将UTF-8编码的char
指针解码为原始unsigned
代码点。但是,某些平面无法正确解码。我们来看看(相关)代码:
typedef struct string {
unsigned long length;
unsigned *data;
} string;
// really simple stuff
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;
}
// UTF-8 conversions
string ctou(char *old) {
unsigned long i, byte = 0, cur = 0;
string new;
new.length = 0;
for (i = 0; old[i]; i++)
if (old[i] < 0x80) upush(&new, old[i]);
else if (old[i] < 0xc0)
if (!byte) {
byte = cur = 0;
continue;
} else {
cur |= (unsigned)(old[i] & 0x3f) << (6 * (--byte));
if (!byte) upush(&new, cur), cur = 0;
}
else if (old[i] < 0xc2) continue;
else if (old[i] < 0xe0) {
cur = (unsigned)(old[i] & 0x1f) << 6;
byte = 1;
}
else if (old[i] < 0xf0) {
cur = (unsigned)(old[i] & 0xf) << 12;
byte = 2;
}
else if (old[i] < 0xf5) {
cur = (unsigned)(old[i] & 0x7) << 18;
byte = 3;
}
else continue;
return new;
}
顺便说一句,所有upush
都会将代码点推送到string
的末尾,根据需要重新分配内存。 ctou
执行解码工作,并在byte
中存储序列中仍需要的字节数,以及cur
中正在进行的代码点。
代码似乎对我来说都是正确的。让我们尝试解码U+10ffff
,即UTF-8中的f4 8f bf bd
。这样做:
long i;
string b = ctou("\xf4\x8f\xbf\xbd");
for (i = 0; i < b.length; i++)
printf("%z ", b.data[i]);
应打印出来:
10ffff
但是打印出来:
fffffff4 ffffff8f ffffffbf ffffffbd
基本上是UTF-8的四个字节,在它之前加上ffffff
。
关于我的代码中有什么问题的任何指导?
答案 0 :(得分:4)
允许对char类型进行签名,转换为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;
}
打印:
FFFFFFF4
FFFFFFF4
改为使用unsigned char。
答案 1 :(得分:2)
您可能忽略了char
是您平台上已签名类型的事实。始终使用:
unsigned char
如果您要读取字节的实际值signed char
如果您使用字节作为小型有符号整数char
表示您不关心值的抽象字符串,除非可能为0。顺便说一下,你的代码效率非常低。为什么不分配realloc
来开始,而不是一次性地调用sizeof(unsigned)*(strlen(old)+1)
,如果它太大,那么减小最后的大小?当然,这只是许多效率低下的原因之一。