簡體   English   中英

UTF-8解碼器在非ASCII字符上失敗

[英]UTF-8 decoder fails on non-ASCII characters

注意:如果您關注了我最近的問題,您會發現它們全都與我在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

關於我的代碼有什么問題的任何指導?

允許對char類型進行簽名,並且先轉換為int然后再進行無符號轉換(當您直接轉換為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。

您可能已經忽略了char是平台上的帶符號類型這一事實。 始終使用:

  • unsigned char如果要讀取字節的實際值)
  • 如果您使用字節作為小符號整數,則為signed char
  • char代表抽象字符串,在這里您不需要關心任何值,除了0之外。

順便說一句,您的代碼效率極低。 而不是一遍又一遍地按字符調用realloc ,為什么不先分配sizeof(unsigned)*(strlen(old)+1) ,然后如果太大則減小其大小? 當然,這只是許多低效率中的一種。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM