我需要一个能:
'\0'长度必须为0的特例返回编码长度对于如何处理无效序列,我没有特别的要求,因此我选择了以下行为:
"\xFF\x2F",它将返回'\xFF'作为值,1作为长度)。我编写了以下函数:
static uint8_t LEN[] = {1,1,1,1,2,2,3,0};
static uint8_t MSK[] = {0,0,3,4,5,0,0,0};
static int utf8_cp(char *txt, int32_t *ch)
{
int len = 0;
int32_t val = 0;
uint8_t first = (uint8_t)(*txt);
len = (first > 0) * (1 + ((first & 0xC0) == 0xC0) * LEN[(first >> 3) & 7]);
val = first & (0xFF >> MSK[len]);
for (int k=len; k>1; k--) {
if ((*++txt & 0xC0) != 0x80) {
val = first;
len = 1;
break;
}
val = (val << 6) | (*txt & 0x3F);
}
*ch = val;
return len;
}所以这样的代码:
char *t; int l; int32_t c;
t = "aàも";
while(1) {
l = utf8_cp(t, &c);
printf("'%s' len:%d cp:0x%05x\n", t, l, c);
if (*t == 0) break;
t += l;
} 生产:
'aàも' len:1 cp:0x00061
'àも' len:2 cp:0x000e0
'も' len:3 cp:0x03082
'' len:4 cp:0x2b014
'' len:0 cp:0x00000为了使它更快,我考虑了展开for循环(但我想知道我能得到多少),并在开始时引入一些if来处理ASCII字符(但我担心分支比做一堆操作代价更高)。
我将感谢您的任何意见和任何改进建议。
发布于 2016-09-21 01:44:47
不要使用狭窄的类型,而是使用最快的类型。
// uint8_t first = (uint8_t)(*txt);
unsigned first = (uint8_t)(*txt);
// or
uint_fast8_t first = (uint8_t)(*txt);与其查找要移位的值,不如向上查找移位的值。
// static uint8_t MSK[] = {0,0,3,4,5,0,0,0};
// val = first & (0xFF >> MSK[len]);
static const uint8_t FF_MSK[] = {0xFF >>0, 0xFF >>0, 0xFF >>3,
0xFF >>4, 0xFF >>5, 0xFF >>0, 0xFF >>0, 0xFF >>0};
val = first & FF_MSK[len];如果已知指针不重叠,一些现代编译器可以进行额外的优化--在适用的情况下使用restrict和const。
// int utf8_cp(char *txt, int32_t *ch)
int utf8_cp(const char * restrict txt, int32_t *restrict ch)编写配套函数将有助于对这两个函数进行测试。
int utf8_cp_encode(int32_t *ch, char *txt);由于代码不会检测到max_Unicode上的代理、冗余模式和值等无效编码,所以我认为只处理无效序列的子集没有什么价值。要么检测它们全部(可能处于调试模式),要么跳过检测。
建议进行32字节(或256字节)的查找以提高性能。找出最佳配置文件。
// len = (first > 0) * (1 + ((first & 0xC0) == 0xC0) * LEN[(first >> 3) & 7]);
len = (first > 0) * LEN_32[first >> 3];
// or
len = LEN_256[first];可以将上面的内容扩展到对len和val进行一次查找。
https://codereview.stackexchange.com/questions/141975
复制相似问题