Ответ 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...
означает три байта, и т.д.).