Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

UTF-8 & Unicode, what's with 0xC0 and 0x80?

Tags:

unicode

utf-8

I've been reading about Unicode and UTF-8 in the last couple of days and I often come across a bitwise comparison similar to this :

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

Can someone clarify the comparison with 0xc0 and checking if it's the most significant bit ?

Thank you!

EDIT: ANDed, not comparison, used the wrong word ;)

like image 487
vdsf Avatar asked Oct 12 '10 03:10

vdsf


People also ask

What UTF-8 means?

UTF-8 (UCS Transformation Format 8) is the World Wide Web's most common character encoding. Each character is represented by one to four bytes. UTF-8 is backward-compatible with ASCII and can represent any standard Unicode character.

What is the UTF-8 Value for?

UTF-8 (Unicode Transformation–8-bit) is an encoding defined by the International Organization for Standardization (ISO) in ISO 10646. It can represent up to 2,097,152 code points (2^21), more than enough to cover the current 1,112,064 Unicode code points.

Is UTF-8 and ASCII same?

For characters represented by the 7-bit ASCII character codes, the UTF-8 representation is exactly equivalent to ASCII, allowing transparent round trip migration. Other Unicode characters are represented in UTF-8 by sequences of up to 6 bytes, though most Western European characters require only 2 bytes3.

Is UTF-8 or UTF-16 better?

UTF-16 is better where ASCII is not predominant, since it uses 2 bytes per character, primarily. UTF-8 will start to use 3 or more bytes for the higher order characters where UTF-16 remains at just 2 bytes for most characters.


1 Answers

It's not a comparison with 0xc0, it's a logical AND operation with 0xc0.

The bit mask 0xc0 is 11 00 00 00 so what the AND is doing is extracting only the top two bits:

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

This is then compared to 0x80 (binary 10 00 00 00). In other words, the if statement is checking to see if the top two bits of the value are not equal to 10.

"Why?", I hear you ask. Well, that's a good question. The answer is that, in UTF-8, all bytes that begin with the bit pattern 10 are subsequent bytes of a multi-byte sequence:

                    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 

So, what this little snippet is doing is going through every byte of your UTF-8 string and counting up all the bytes that aren't continuation bytes (i.e., it's getting the length of the string, as advertised). See this wikipedia link for more detail and Joel Spolsky's excellent article for a primer.


An interesting aside by the way. You can classify bytes in a UTF-8 stream as follows:

  • With the high bit set to 0, it's a single byte value.
  • With the two high bits set to 10, it's a continuation byte.
  • Otherwise, it's the first byte of a multi-byte sequence and the number of leading 1 bits indicates how many bytes there are in total for this sequence (110... means two bytes, 1110... means three bytes, etc).
like image 127
paxdiablo Avatar answered Sep 23 '22 09:09

paxdiablo