Подтвердить что ты не робот

UTF-8 и Unicode, что с 0xC0 и 0x80?

Я читал об Unicode и UTF-8 за последние пару дней, и я часто встречаю побитное сравнение, подобное этому:

int strlen_utf8(char *s) 
{
  int i = 0, j = 0;
  while (s[i]) 
  {
    if ((s[i] & 0xc0) != 0x80) j++;
    i++;
  }
  return j;
}

Может ли кто-нибудь уточнить сравнение с 0xc0 и проверить, является ли это самым значимым битом?

Спасибо!

EDIT: ANDed, а не сравнение, использовали неправильное слово;)

4b9b3361

Ответ 1

Это не сравнение с 0xc0, это логическая операция И с 0xc0.

Бит-маска 0xc0 равна 11 00 00 00, поэтому то, что делает AND, - это извлечение только двух верхних бит:

    ab cd ef gh
AND 11 00 00 00
    -- -- -- --
  = ab 00 00 00

Затем сравнивается с 0x80 (двоичный 10 00 00 00). Другими словами, оператор if проверяет, не соответствуют ли верхние два бита значениям 10.

"Почему?", я слышал, вы спрашиваете. Ну, это хороший вопрос. Ответ заключается в том, что в UTF-8 все байты, начинающиеся с битового шаблона 10, являются последующими байтами многобайтовой последовательности:

                    UTF-8
Range              Encoding  Binary value
-----------------  --------  --------------------------
U+000000-U+00007f  0xxxxxxx  0xxxxxxx

U+000080-U+0007ff  110yyyxx  00000yyy xxxxxxxx
                   10xxxxxx

U+000800-U+00ffff  1110yyyy  yyyyyyyy xxxxxxxx
                   10yyyyxx
                   10xxxxxx

U+010000-U+10ffff  11110zzz  000zzzzz yyyyyyyy xxxxxxxx
                   10zzyyyy
                   10yyyyxx
                   10xxxxxx

Итак, что делает этот маленький фрагмент, проходит через каждый байт строки вашего UTF-8 и подсчитывает все байты, которые не являются байтами продолжения (т.е. он получает длину строки, как объявлено). См. эту ссылку в Википедии для более подробной информации и Joel Spolsky отличная статья для праймера.


Интересно, кстати. Вы можете классифицировать байты в потоке UTF-8 следующим образом:

  • С высоким битом, установленным в 0, это однобайтовое значение.
  • С двумя старшими битами, установленными в 10, это байт продолжения.
  • В противном случае это первый байт многобайтовой последовательности, а число ведущих бит 1 указывает, сколько байтов в общей сложности для этой последовательности (110... означает два байта, 1110... означает три байта, и т.д.).