Take the 2-minute tour ×
Programmers Stack Exchange is a question and answer site for professional programmers interested in conceptual questions about software development. It's 100% free, no registration required.

I'm going to ask what is probably quite a controversial question: "Should one of the most popular encodings, UTF-16, be considered harmful?"

Why do I ask this question?

How many programmers are aware of the fact that UTF-16 is actually a variable length encoding? By this I mean that there are code points that, represented as surrogate pairs, take more than one element.

I know; lots of applications, frameworks and APIs use UTF-16, such as Java's String, C#'s String, Win32 APIs, Qt GUI libraries, the ICU Unicode library, etc. However, with all of that, there are lots of basic bugs in the processing of characters out of BMP (characters that should be encoded using two UTF-16 elements).

For example, try to edit one of these characters:

  • 𠂊 (U+2008A) Han Character

You may miss some, depending on what fonts you have installed. These characters are all outside of the BMP (Basic Multilingual Plane). If you cannot see these characters, you can also try looking at them in the Unicode Character reference.

For example, try to create file names in Windows that include these characters; try to delete these characters with a "backspace" to see how they behave in different applications that use UTF-16. I did some tests and the results are quite bad:

  • Opera has problem with editing them (delete required 2 presses on backspace)
  • Notepad can't deal with them correctly (delete required 2 presses on backspace)
  • File names editing in Window dialogs in broken (delete required 2 presses on backspace)
  • All QT3 applications can't deal with them - show two empty squares instead of one symbol.
  • Python encodes such characters incorrectly when used directly u'X'!=unicode('X','utf-16') on some platforms when X in character outside of BMP.
  • Python 2.5 unicodedata fails to get properties on such characters when python compiled with UTF-16 Unicode strings.
  • StackOverflow seems to remove these characters from the text if edited directly in as Unicode characters (these characters are shown using HTML Unicode escapes).
  • WinForms TextBox may generate invalid string when limited with MaxLength.

It seems that such bugs are extremely easy to find in many applications that use UTF-16.

So... Do you think that UTF-16 should be considered harmful?

share|improve this question
The double backspace behavior is mostly intentional blogs.msdn.com/michkap/archive/2005/12/21/506248.aspx –  CiscoIPPhone Jun 27 '09 at 10:56
Not really correct. I explain, if you write "שָׁ" the compound character that consists of "ש",‎ "ָ" and "ׁ", vovels, then removal of each one of them is logical, you remove one code-point when you press "backspace" and remove all character including vovels when press "del". But, you never produce illegal state of text -- illegal code points. Thus, the situation when you press backspace and get illegat text is incorrect. –  Artyom Jun 27 '09 at 12:43
CiscoIPPhone: If a bug is "reported several different times, by many different people", and then a couple years later a developer writes on a dev blog that "Believe it or not, the behavior is mostly intentional!", then (to put it mildly) I tend to think it's probably not the best design decision ever made. :-) Just because it's intentional doesn't mean it's not a bug. –  Ken Mar 18 '10 at 1:18
Great post. UTF-16 is indeed the "worst of both worlds": UTF8 is variable-length, covers all of Unicode, requires a transformation algorithm to and from raw codepoints, restricts to ASCII, and it has no endianness issues. UTF32 is fixed-length, requires no transformation, but takes up more space and has endianness issues. So far so good, you can use UTF32 internally and UTF8 for serialization. But UTF16 has no benefits: It's endian-dependent, it's variable length, it takes lots of space, it's not ASCII-compatible. The effort needed to deal with UTF16 properly could be spent better on UTF8. –  Kerrek SB Jun 9 '11 at 11:38
@Ian: UTF-8 DOES NOT have the same caveats as UTF-8. You cannot have surrogates in UTF-8. UTF-8 does not masquerade as something it’s not, but most programmers using UTF-16 are using it wrong. I know. I've watched them again and again and again and again. –  tchrist Aug 15 '11 at 19:44
show 32 more comments

migrated from stackoverflow.com Aug 18 '11 at 21:32

This question came from our site for professional and enthusiast programmers.

22 Answers

up vote 295 down vote accepted

UTF-8 Everywhere has the latest updates to this answer.

Opinion: Yes, UTF-16 should be considered harmful. The very reason it exists is because some time ago there used to be a misguided belief that widechar is going to be what UCS-4 now is.

Despite the "anglo-centrism" of UTF-8, it should be considered the only useful encoding for text. One can argue that source codes of programs, web pages and XML files, OS file names and other computer-to-computer text interfaces should never have existed. But when they do, text is not only for human readers.

On the other hand, UTF-8 overhead is a small price to pay while it has significant advantages. Advantages such as compatibility with unaware code that just passes strings with char*. This is a great thing. There're few useful characters which are SHORTER in UTF-16 than they are in UTF-8.

I believe that all other encodings will die eventually. This involves that MS-Windows, Java, ICU stop using it as their favorite. After long research and discussions, the development conventions at my company ban using UTF-16 anywhere except OS API calls, and this despite importance of performance in our applications and the fact that we use Windows. Conversion functions were developed to convert always-assumed-UTF8 std::strings to native UTF-16, which Windows itself does not support properly.

To people who say "use what needed where it is needed", I say: there's a huge advantage to using the same encoding everywhere, and I see no sufficient reason to do otherwise. In particular, I think adding wchar_t to C++ was a mistake, and so are the Unicode additions to C++0x. What must be demanded from STL implementations though is that every std::string or char* parameter would be considered unicode-compatible.

I am also against the "use what you want" approach. I see no reason for such liberty. There's enough confusion on the subject of text, resulting in all this broken software. Having above said, I am convinced that programmers must finally reach consensus on UTF-8 as one proper way. (I come from a non-ascii-speaking country and grew up on Windows, so I'd be last expected to attack UTF-16 based on religious grounds).

I'd like to share more information on how I do text on Windows, and what I recommend to everyone else for compile-time checked unicode correctness, ease of use and better multi-platformness of the code. The suggestion substantially differs from what is usually recommended as the proper way of using Unicode on windows. Yet, in depth research of these recommendations resulted in the same conclusion. So here goes:

  • Do not use wchar_t or std::wstring in any place other than adjacent point to APIs accepting UTF-16.
  • Don't use _T("") or L"" UTF-16 literals (These should IMO be taken out of the standard, as a part of UTF-16 deprecation).
  • Don't use types, functions or their derivatives that are sensitive to the _UNICODE constant, such as LPTSTR or CreateWindow().
  • Yet, _UNICODE always defined, to avoid passing char* strings to WinAPI getting silently compiled
  • std::strings and char* anywhere in program are considered UTF-8 (if not said otherwise)
  • All my strings are std::string, though you can pass char* or string literal to convert(const std::string &).
  • only use Win32 functions that accept widechars (LPWSTR). Never those which accept LPTSTR or LPSTR. Pass parameters this way:

    ::SetWindowTextW(Utils::convert(someStdString or "string litteral").c_str())

    (The policy uses conversion functions below.)

  • With MFC strings:

    CString someoneElse; // something that arrived from MFC. Converted as soon as possible, before passing any further away from the API call:
    std::string s = str(boost::format("Hello %s\n") % Convert(someoneElse));
    AfxMessageBox(MfcUtils::Convert(s), _T("Error"), MB_OK);
  • Working with files, filenames and fstream on Windows:

    • Never pass std::string or const char* filename arguments to fstream family. MSVC STL does not support UTF-8 arguments, but has a non-standard extension which should be used as follows:
    • Convert std::string arguments to std::wstring with Utils::Convert:

      std::ifstream ifs(Utils::Convert("hello"),
                        std::ios_base::in |

      We'll have to manually remove the convert, when MSVC's attitude to fstream changes.

    • This code is not multi-platform and may have to be changed manually in the future
    • See fstream unicode research/discussion case 4215 for more info.
    • Never produce text output files with non-UTF8 content
    • Avoid using fopen() for RAII/OOD reasons. If necessary, use _wfopen() and WinAPI conventions above.

// For interface to win32 API functions
std::string convert(const std::wstring& str, unsigned int codePage /*= CP_UTF8*/)
    // Ask me for implementation..

std::wstring convert(const std::string& str, unsigned int codePage /*= CP_UTF8*/)
    // Ask me for implementation..

// Interface to MFC
std::string convert(const CString &mfcString)
#ifdef UNICODE
    return Utils::convert(std::wstring(mfcString.GetString()));
    return mfcString.GetString();   // This branch is deprecated.

CString convert(const std::string &s)
#ifdef UNICODE
    return CString(Utils::convert(s).c_str());
    Exceptions::Assert(false, "Unicode policy violation. See W569"); // This branch is deprecated as it does not support unicode
    return s.c_str();   
share|improve this answer
I can't agree. The advantages of utf16 over utf8 for many Asian languages completely dominate the points you make. It is naive to hope that the Japanese, Thai, Chinese, etc. are going to give up this encoding. The problematic clashes between charsets are when the charsets mostly seem similar, except with differences. I suggest standardising on: fixed 7bit: iso-irv-170; 8bit variable: utf8; 16bit variable: utf16; 32bit fixed: ucs4. –  Charles Stewart Dec 9 '09 at 15:24
@Charles: thanks for your input. True, some BMP characters are longer in UTF-8 than in UTF-16. But, let's face it: the problem is not in bytes that BMP Chinese characters take, but the software design complexity that arises. If a Chinese programmer has to design for variable-length characters anyway, it seems like UTF-8 is still a small price to pay compared to other variables in the system. He might use UTF-16 as a compression algorithm if space is so important, but even then it will be no match for LZ, and after LZ or other generic compression both take about the same size and entropy. –  Pavel Radzivilovsky Dec 9 '09 at 18:04
What I basically say is that simplification offered by having One encoding that is also compatible with existing char* programs, and is also the most popular today for everything is unimaginable. It is almost like in good old "plaintext" days. Want to open a file with a name? No need to care what kind of unicode you are doing, etc etc. I suggest we, developers, confine UTF-16 to very special cases of severe optimization where a tiny bit of performance is worth man-months of work. –  Pavel Radzivilovsky Dec 9 '09 at 18:08
Linux has had a specific requirement when choosing to use UTF-8 internally: compatibility with Unix. Windows didn't need that, and thus when the developers implemented Unicode, they added UCS-2 versions of almost all functions handling text and made the multibyte ones simply convert to UCS-2 and call the other ones. THey later replaces UCS-2 with UTF-16. Linux on the other hand kept to 8-bit encodings and thus used UTF-8, as it's the proper choice in that case. –  Mircea Chirea Mar 17 '10 at 17:56
@Pavel Radzivilovsky: BTW, your writings about "I believe that all other encodings will die eventually. This involves that MS-Windows, Java, ICU, python stop using it as their favorite." and "In particular, I think adding wchar_t to C++ was a mistake, and so are the unicode additions to C++Ox." are either quite naive or very very arrogant. And this is coming from someone coding at home with a Linux and who is happy with the UTF-8 chars. To put it bluntly: It won't happen. –  paercebal Sep 4 '10 at 12:28
show 41 more comments

Unicode codepoints are not characters! Sometimes they are not even glyphs (visual forms).

Some examples:

  • Roman numeral codepoints like "ⅲ". (A single character that looks like "iii".)
  • Accented characters like "á", which can be represented as either a single combined character "\u00e1" or a character and separated diacritic "\u0061\u0301".
  • Characters like Greek lowercase sigma, which have different forms for middle ("σ") and end ("ς") of word positions, but which should be considered synonyms for search.
  • Unicode discretionary hyphen U+00AD, which might or might not be visually displayed, depending on context, and which is ignored for semantic search.

The only ways to get Unicode editing right is to use a library written by an expert, or become an expert and write one yourself. If you are just counting codepoints, you are living in a state of sin.

share|improve this answer
This. Very much this. UTF-16 can cause problems, but even using UTF-32 throughout can (and will) still give you issues. –  bcat Dec 24 '10 at 0:48
What is a character? You can define a code point as a character and get by pretty much just fine. If you mean a user-visible glyph, that’s something else. –  tchrist Aug 11 '11 at 14:54
@tchrist sure for allocating space that definition is fine, but for anything else? Not so much. If you handle a combining character as a sole character (ie for a delete or "take first N characters" operation) you'll get strange and wrong behavior. If a code point has only meaning when combined with at least another you can't handle it on its own in any sensible manner. –  Voo Aug 15 '11 at 15:28
@Pacerier, this is late to the party, but I have to comment on that. Some languages have very large sets of potential combinations of diacritics (c.f. Vietnamese, i.e. mệt đừ). Having combinations rather than one character per diacritic is very helpful. –  syrion Apr 20 '12 at 21:23
a small note on terminology: codepoints do correspond to unicode characters; what Daniel is talking about here are user-perceived characters, which correspond to unicode grapheme clusters –  Christoph Apr 21 '12 at 11:58
show 4 more comments

There is a simple rule of thumb on what Unicode Transformation Form (UTF) to use: - utf-8 for storage and comunication - utf-16 for data processing - you might go with utf-32 if most of the platform API you use is utf-32 (common in the UNIX world).

Most systems today use utf-16 (Windows, Mac OS, Java, .NET, ICU, Qt). Also see this document: http://unicode.org/notes/tn12/

Back to "UTF-16 as harmful", I would say: definitely not.

People who are afraid of surrogates (thinking that they transform Unicode into a variable-length encoding) don't understand the other (way bigger) complexities that make mapping between characters and a Unicode code point very complex: combining characters, ligatures, variation selectors, control characters, etc.

Just read this series here http://blogs.msdn.com/michkap/archive/2009/06/29/9800913.aspx and see how UTF-16 becomes an easy problem.

share|improve this answer
Please add some examples where UTF-32 is common in the UNIX world! –  maxschlepzig Jan 13 '11 at 13:39
No, you do not want to use UTF-16 for data processing. It's a pain in the ass. It has all the disadvantages of UTF-8 but none of its advantages. Both UTF-8 and UTF-32 are clearly superior to the vicious hack previously known as Mrs UTF-16, whose maiden name was UCS-2. –  tchrist Aug 11 '11 at 14:18
I yesterday just found a bug in the Java core String class’s equalsIgnoreCase method (also others in the string class) that would never have been there had Java used either UTF-8 or UTF-32. There are millions of these sleeping bombshells in any code that uses UTF-16, and I am sick and tired of them. UTF-16 is a vicious pox that plagues our software with insidious bugs forever and ever. It is clearly harmful, and should be deprecated and banned. –  tchrist Aug 11 '11 at 14:53
@tchrist Wow so a non-surrogate aware function (because it was written when there were none and is sadly documented in such a way that makes it probably impossible to adapt - it specifies .toUpperCase(char)) will result in the wrong behavior? You're aware that a UTF-32 function with an outdated code point map wouldn't handle this any better? Also the whole Java API handles surrogates not especially well and the more intricate points about Unicode not at all - and with the later the used encoding wouldn't matter at all. –  Voo Aug 15 '11 at 15:32
There is absolutely no reason to use UTF-16 for data processing. –  niXar Aug 18 '11 at 20:02
show 2 more comments

I would suggest that thinking UTF-16 might be considered harmful says that you need to gain a greater understanding of unicode.

Since I've been downvoted for presenting my opinion on a subjective question, let me elaborate. What exactly is it that bothers you about UTF-16? Would you prefer if everything was encoded in UTF-8? UTF-7? Or how about UCS-4? Of course certain applications are not designed to handle everysingle character code out there - but they are necessary, especially in today's global information domain, for communication between international boundaries.

But really, if you feel UTF-16 should be considered harmful because it's confusing or can be improperly implemented (unicode certainly can be), then what method of character encoding would be considered non-harmful?

EDIT: To clarify: Why consider improper implementations of a standard a reflection of the quality of the standard itself? As others have subsequently noted, merely because an application uses a tool inappropriately, does not mean that the tool itself is defective. If that were the case, we could probably say things like "var keyword considered harmful", or "threading considered harmful". I think the question confuses the quality and nature of the standard with the difficulties many programmers have in implementing and using it properly, which I feel stem more from their lack of understanding how unicode works, rather than unicode itself.

share|improve this answer
-1: How about addressing some of Artyom's objections, rather than just patronising him? –  RichieHindle Jun 26 '09 at 16:12
BTW: When I started writing this article I almost wanted to write "Does Joel on Softeare article of Unicode should be considered harmful" because there are many mistakes. For example: utf-8 encoding takes up to 4 characters and not 6. Also it does not distinguish between UCS-2 and UTF-16 that are really different -- and actually cause the problems I talk about. –  Artyom Jun 26 '09 at 16:12
Also, it should be noted that when Joel wrote that article, the UTF-8 standard WAS 6 bytes, not 4. RFC 3629 changed the standard to 4 bytes several months AFTER he wrote the article. Like most anything on the internet, it pays to read from more than one source, and to be aware of the age of your sources. The link wasn't intended to be the "end all be all", but rather a starting point. –  patjbs Jun 26 '09 at 16:42
I would pic: utf-8 or utf-32 that are: variable length encoding in almost all cases (including BMP) or fixed length encoding always. –  Artyom Jul 12 '09 at 6:50
@iconiK: Don’t be silly. UTF-16 is absolutely not the de facto standard for processing text. Show me a programming lanuage more suited to text processing that Perl, which has always (well, for more than a decade) used abstract characters with an underlying UTF-8 representation internally. Because of this, every Perl program automatically handles all Unicode without the user having to constantly monkey around with idiotic surrogates. The length of a string is its count in code points, not code units. Anything else is sheer stupidity putting the backwards into backwards compatibility. –  tchrist Aug 11 '11 at 14:50
show 9 more comments

There is nothing wrong with Utf-16 encoding. But languages that treat the 16-bit units as characters should probably be considered badly designed. Having a type named 'char' which does not always represent a character is pretty confusing. Since most developers will expect a char type to represent a code point or character, much code will probably break when exposed to characters beyound BMP.

Note however that even using utf-32 does not mean that each 32-bit code point will always represent a character. Due to combining characters, an actual character may consist of several code points. Unicode is never trivial.

BTW. There is probably the same class of bugs with platforms and applications which expect characters to be 8-bit, which are fed Utf-8.

share|improve this answer
In Java's case, if you look at their timeline (java.com/en/javahistory/timeline.jsp), you see that the primarily development of String happened while Unicode was 16 bits (it changed in 1996). They had to bolt on the ability to handle non BMP code points, thus the confusion. –  Kathy Van Stone Jun 26 '09 at 17:40
@Kathy: Not really an excuse for C#, though. Generally, I agree, that there should be a CodePoint type, holding a single code point (21 bits), a CodeUnit type, holding a single code unit (16 bits for UTF-16) and a Character type would ideally have to support a complete grapheme. But that makes it functionally equivalent to a String ... –  Joey Apr 2 '10 at 13:43
This answer is almost two years old, but I can't help but comment on it. "Having a type named 'char' which does not always represent a character is pretty confusing." And yet people use it all the time in C and the like to represent integer data that can be stored in a single byte. –  JAB Jun 6 '11 at 15:53
C# has a different excuse: it was designed for Windows, and Windows was built on UCS-2 (it's very annoying that even today Windows APIs cannot support UTF-8). Plus, I think Microsoft wanted Java compatibility (.NET 1.0 had a Java compatibility library, but they dropped Java support very quickly--I'm guessing this is due to Sun's lawsuit against MS?) –  Qwertie May 1 '12 at 0:05
show 1 more comment

Yes, absolutely.

Why? It has to do with exercising code.

If you look at these codepoint usage statistics on a large corpus by Tom Christiansen you'll see that trans-8bit BMP codepoints are used several orders if magnitude more than non-BMP codepoints:

 2663710 U+002013 ‹–›  GC=Pd    EN DASH
 1065594 U+0000A0 ‹ ›  GC=Zs    NO-BREAK SPACE
 1009762 U+0000B1 ‹±›  GC=Sm    PLUS-MINUS SIGN
  784139 U+002212 ‹−›  GC=Sm    MINUS SIGN
  602377 U+002003 ‹ ›  GC=Zs    EM SPACE


Take the TDD dictum: "Untested code is broken code", and rephrase it as "unexercised code is broken code", and think how often programmers have to deal with non-BMP codepoints.

Bugs related to not dealing with UTF-16 as a variable-width encoding are much more likely to go unnoticed than the equivalent bugs in UTF-8. Some programming languages still don't guarantee to give you UTF-16 instead of UCS-2, and some so-called high-level programming languages offer access to code units instead of code-points (even C is supposed to give you access to codepoints if you use wchar_t, regardless of what some platforms may do).

share|improve this answer
"Bugs related to not dealing with UTF-16 as a variable-width encoding are much more likely to go unnoticed than the equivalent bugs in UTF-8." This is the core of the issue, and hence, the correct answer. –  Sean McMillan Aug 19 '11 at 13:01
Precisely. If your UTF-8 handling is borked, it'll be immediately obvious. If your UTF-8 handling is borked, you'll only notice if you put in uncommon Han characters or math symbols. –  Mechanical snail Aug 1 '12 at 7:26
add comment

My personal choice is to always use UTF-8. It's the standard on Linux for nearly everything. It's backwards compatible with many legacy apps. There is a very minimal overhead in terms of extra space used for non-latin characters vs the other UTF formats, and there is a significant savings in space for latin characters. On the web, latin languages reign supreme, and I think they will for the foreseeable future. And to address one of the main arguments in the original post: nearly every programmer is aware that UTF-8 will sometimes have multi-byte characters in it. Not everyone deals with this correctly, but they are usually aware, which is more than can be said for UTF-16. But, of course, you need to choose the one most appropriate for your application. That's why there's more than one in the first place.

share|improve this answer
UTF-16 is simpler for anything inside BMP, that's why it is used so widely. But I'm a fan of UTF-8 too, it also has no problems with byte order, which works to its advantage. –  Malcolm Jun 26 '09 at 16:57
Theoretically, yes. In practice there are such things as, say, UTF-16BE, which means UTF-16 in big endian without BOM. This is not some thing I made up, this is an actual encoding allowed in ID3v2.4 tags (ID3v2 tags suck, but are, unfortunately, widely used). And in such cases you have to define endianness externally, because the text itself doesn't contain BOM. UTF-8 is always written one way and it doesn't have such a problem. –  Malcolm Apr 2 '10 at 15:33
No, UTF-16 is not simpler. It is harder. It misleads and deceives you into thinking it is fixed width. All such code is broken and all the moreso because you don’t notice until it’s too late. CASE IN POINT: I just found yet another stupid UTF-16 bug in the Java core libraries yesterday, this time in String.equalsIgnoreCase, which was left in UCS-2 braindeath buggery, and so fails on 16/17 valid Unicode code points. How long has that code been around? No excuse for it to be buggy. UTF-16 leads to sheer stupidity and an accident waiting to happen. Run screaming from UTF-16. –  tchrist Aug 11 '11 at 14:42
@tchrist One must be a very ignorant developer to not know that UTF-16 is not fixed length. If you start with Wikipedia, you will read the following at the very top: "It produces a variable-length result of either one or two 16-bit code units per code point". Unicode FAQ says the same: unicode.org/faq//utf_bom.html#utf16-1. I don't know, how UTF-16 can deceive anybody if it is written everywhere that it is variable length. As for the method, it was never designed for UTF-16 and shouldn't be considered Unicode, as simple as that. –  Malcolm Aug 13 '11 at 10:30
@tchrist Do you have a source for your statistics? Though if good programmers a scarce, I think this is good, because we become more valuable. :) As for the Java APIs, char-based parts may eventually get deprecated, but this is not a guarantee that they won't be used. And they definitely won't be removed for compability reasons. –  Malcolm Aug 16 '11 at 8:29
show 3 more comments

Well, there is an encoding that uses fixed-size symbols. I certainly mean UTF-32. But 4 bytes for each symbol is too much of wasted space, why would we use it in everyday situations?

To my mind, most problems appear from the fact that some software fell behind the Unicode standard, but were not quick to correct the situation. Opera, Windows, Python, Qt - all of them appeared before UTF-16 became widely known or even came into existence. I can confirm, though, that in Opera, Windows Explorer, and Notepad there are no problems with characters outside BMP anymore (at least on my PC). But anyway, if programs don't recognise surrogate pairs, then they don't use UTF-16. Whatever problems arise from dealing with such programs, they have nothing to do with UTF-16 itself.

However, I think that the problems of legacy software with only BMP support are somewhat exaggerated. Characters outside BMP are encountered only in very specific cases and areas. According to the Unicode official FAQ, "even in East Asian text, the incidence of surrogate pairs should be well less than 1% of all text storage on average". Of course, characters outside BMP shouldn't be neglected because a program is not Unicode-conformant otherwise, but most programs are not intended for working with texts containing such characters. That's why if they don't support it, it is unpleasant, but not a catastrophy.

Now let's consider the alternative. If UTF-16 didn't exist, then we wouldn't have an encoding which is well-suited for non-ASCII text, and all the software created for UCS-2 would have to be completely redesigned to remain Unicode-compliant. The latter most likely would only slow Unicode adoption. Also we wouldn't have been able to maintain compability with text in UCS-2 like UTF-8 does in relation to ASCII.

Now, putting aside all the legacy issues, what are the arguments against the encoding itself? I really doubt that developers nowadays don't know that UTF-16 is variable length, it is written everywhere strarting with Wikipedia. UTF-16 is much less difficult to parse than UTF-8, if someone pointed out complexity as a possible problem. Also it is wrong to think that it is easy to mess up with determining the string length only in UTF-16. If you use UTF-8 or UTF-32, you still should be aware that one Unicode code point doesn't necessarily mean one character. Other than that, I don't think that there's anything substantial against the encoding.

Therefore I don't think the encoding itself should be considered harmful. UTF-16 is a compromise between simplicity and compactness, and there's no harm in using what is needed where it is needed. In some cases you need to remain compatible with ASCII and you need UTF-8, in some cases you want to work with work with Han ideographs and conserve space using UTF-16, in some cases you need universal representations of characters usign a fixed-length encoding. Use what's more appropriate, just do it properly.

share|improve this answer
That's a rather blinkered, Anglo-centric view, Malcolm. Almost on a par with "ASCII is good enough for the USA - the rest of the world should fit in with us". –  Jonathan Leffler Jun 26 '09 at 16:22
Actually I'm from Russia and encounter cyrillics all the time (including my own programs), so I don't think that I have Anglo-centric view. :) Mentioning ASCII is not quite appropirate, because it's not Unicode and doesn't support specific characters. UTF-8, UTF-16, UTF-32 support the very same international character sets, they are just intended for use in their specific areas. And this is exactly my point: if you use mostly English, use UTF-8, if you use mostly cyrillics, use UTF-16, if you use ancient languages, use UTF-32. Quite simple. –  Malcolm Jun 26 '09 at 16:36
"Not true, Asian scripts like Japanese, Chinese or Arabic belong to BMP also. BMP itself is actually very large and certainly large enough to include all the scripts used nowadays" This is all so wrong. BMP contains 0xFFFF characters (65536). Chinese alone has more than that. Chinese standards (GB 18030) has more than that. Unicode 5.1 already allocated more than 100,000 characters. –  Mihai Nita Jul 24 '09 at 8:11
@Marcolm: "BMP itself is actually very large and certainly large enough to include all the scripts used nowadays" Not true. At this point Unicode already allocated about 100K characters, way more than BMP can accomodate. There are big chunks of Chinese characters outside BMP. And some of them are required by GB-18030 (mandatory Chinese standard). Other are required by (non-mandatory) Japanese and Korean standards. So if you try to sell anything in those markets, you need beyond BMP support. –  Mihai Nita Sep 25 '09 at 21:41
Anything that uses UTF-16 but can only handle narrow BMP characters is not actually using UTF-16. It is buggy and broken. The premise of the OP is sound: UTF-16 is harmful, because it leads naïve people into writing broken code. Either you can handle Unicode text, or you can’t. If you cannot, then you are picking a subset, which is just as stupid as ASCII-only text processing. –  tchrist Aug 11 '11 at 14:46
show 25 more comments

UTF-8 is definitely the way to go, possibly accompanied by UTF-32 for internal use in algorithms that need high performance random access (but that ignores combining chars).

Both UTF-16 and UTF-32 (as well as their LE/BE variants) suffer of endianess issues, so they should never be used externally.

share|improve this answer
Constant time random access is possible with UTF-8 too, just use code units rather than code points. Maybe you need real random code point access, but I've never seen a use case, and you're just as likely to want random grapheme cluster access instead. –  Rhamphoryncus Aug 6 '10 at 7:32
add comment

Years of Windows internationalization work especially in East Asian languages might have corrupted me, but I lean toward UTF-16 for internal-to-the-program representations of strings, and UTF-8 for network or file storage of plaintext-like documents. UTF-16 can usually be processed faster on Windows, though, so that's the primary benefit of using UTF-16 in Windows.

Making the leap to UTF-16 dramatically improved the adequacy of average products handling international text. There are only a few narrow cases when the surrogate pairs need to be considered (deletions, insertions, and line breaking, basically) and the average-case is mostly straight pass-through. And unlike earlier encodings like JIS variants, UTF-16 limits surrogate pairs to a very narrow range, so the check is really quick and works forward and backward.

Granted, it's roughly as quick in correctly-encoded UTF-8, too. But there's also many broken UTF-8 applications that incorrectly encode surrogate pairs as two UTF-8 sequences. So UTF-8 doesn't guarantee salvation either.

IE handles surrogate pairs reasonably well since 2000 or so, even though it typically is converting them from UTF-8 pages to an internal UTF-16 representation; I'm fairly sure Firefox has got it right too, so I don't really care what Opera does.

UTF-32 (aka UCS4) is pointless for most applications since it's so space-demanding, so it's pretty much a nonstarter.

share|improve this answer
I didn't quite get your comment on UTF-8 and surrogate pairs. Surrogate pairs is only a concept that is meaningful in the UTF-16 encoding, right? Perhaps code that converts directly from UTF-16 encoding to UTF-8 encoding might get this wrong, and in that case, the problem is incorrectly reading the UTF-16, not writing the UTF-8. Is that right? –  Craig McQueen Jun 27 '09 at 23:54
What Jason's talking about is software that deliberately implements UTF-8 that way: create a surrogate pair, then UTF-8 encode each half separately. The correct name for that encoding is CESU-8, but Oracle (e.g.) misrepresents it as UTF-8. Java employs a similar scheme for object serialization, but it's clearly documented as "Modified UTF-8" and only for internal use. (Now, if we could just get people to READ that documentation and stop using DataInputStream#readUTF() and DataOutputStream#writeUTF() inappropriately...) –  Alan Moore Jun 28 '09 at 14:35
show 7 more comments

UTF-16? definitely harmful. Just my grain of salt here, but there are exactly three acceptable encodings for text in a program:

  • ASCII: when dealing with low level things (eg: microcontrollers) that can't afford anything better
  • UTF8: storage in fixed-width media such as files
  • integer codepoints ("CP"?): an array of the largest integers that are convenient for your programming language and platform (decays to ASCII in the limit of low resorces). Should be int32 on older computers and int64 on anything with 64-bit addressing.

  • Obviously interfaces to legacy code use what encoding is needed to make the old code work right.

share|improve this answer
@simon buchan, the U+10ffff max will go out the window when (not if) they run out of codepoints. That said, useing int32 on a p64 system for speed is probably safe, since i doubt they'll exceed U+ffffffff before you're forced to rewrite your code for 128 bit systems around 2050. (That is the point of "use the largest int that is convenient" as opposed to "largest available" (which would probably be int256 or bignums or something).) –  David X Jun 10 '10 at 2:59
@David: Your "when" was referring to running out of Unicode codepoints, not a 128-bit switch which, yes, will be in the next few centuries. Unlike memory, there is no exponential growth of characters, so the Unicode Consortium has specifically guaranteed they will never allocate a codepoint above U+10FFFF. This really is one of those situations when 21 bits is enough for anybody. –  Simon Buchan Jun 13 '10 at 2:53
@Simon Buchan: At least until first contact. :) –  dalle Oct 18 '10 at 17:38
Unicode used to guarantee that there would be no code points above U+FFFF too. –  Shannon Severance Oct 4 '13 at 18:47
show 3 more comments

Unicode defines code points up to 0x10FFFF (1,114,112 codes), all applications running in multilingual environment dealing with strings/file names etc. should handle that correctly.

Utf-16: covers only 1,112,064 codes. Although those at the end of Unicode are from planes 15-16 (Private Use Area). It can not grow any further in the future except breaking Utf-16 concept.

Utf-8: covers theoretically 2,216,757,376 codes. Current range of Unicode codes can be represented by maximally 4 byte sequence. It does not suffer with byte order problem, it is "compatible" with ascii.

Utf-32: covers theoretically 2^32=4,294,967,296 codes. Currently it is not variable length encoded and probably will not be in the future.

Those facts are self explanatory. I do not understand advocating general use of Utf-16. It is variable length encoded (can not be accessed by index), it has problems to cover whole Unicode range even at present, byte order must be handled, etc. I do not see any advantage except that it is natively used in Windows and some other places. Even though when writing multi-platform code it is probably better to use Utf-8 natively and make conversions only at the end points in platform dependent way (as already suggested). When direct access by index is necessary and memory is not a problem, Utf-32 should be used.

The main problem is that many programmers dealing with Windows Unicode = Utf-16 do not even know or ignore the fact that it is variable length encoded.

The way it is usually in *nix platform is pretty good, c strings (char *) interpreted as Utf-8 encoded, wide c strings (wchar_t *) interpreted as Utf-32.

share|improve this answer
Note: UTF-16 does covers All Unicode as Unicode Consortium decided that 10FFFF is the TOP range of Unicode and defined UTF-8 maximal 4 bytes length and explicitly excluded range 0xD800-0xDFFF from valid code points range and this range is used for creation of surrogate pairs. So any valid Unicode text can be represented with each of one of these encodings. Also about growing to future. It doesn't seems that 1 Million code points would not be enough in any far future. –  Artyom Jan 21 '11 at 15:06
@Kerrek: Incorrect: UCS-2 is not a valid Unicode encoding. All UTF-* encodings by definition can represent any Unicode code point that is legal for interchange. UCS-2 can represent far fewer than that, plus a few more. Repeat: UCS-2 is not a valid Unicode encoding, any moreso than ASCII is. –  tchrist Aug 11 '11 at 14:33
@Ian Boyd, the need to access a string’s individual character in a random access pattern is incredibly overstated. It is about as common as wanting to compute the diagonal of a matrix of characters, which is super rare. Strings are virtually always processed sequentially, and since accessing UTF-8 char N+1 given that you are at UTF-8 char N is O(1), there is no issue. There is surpassingly little need to make random access of strings. Whether you think it is worth the storage space to go to UTF-32 instead of UTF-8 is your own opinion, but for me, it is altogether a non-issue. –  tchrist Aug 11 '11 at 20:38
show 5 more comments

Add this to the list:

The presented scenario is simple (even more simple as I will present it here than it was originally!): 1.A WinForms TextBox sits on a Form, empty. It has a MaxLength set to 20.

2.The user types into the TextBox, or maybe pastes text into it.

3.No matter what you type or paste into the TextBox, you are limited to 20, though it will sympathetically beep at text beyond the 20 (YMMV here; I changed my sound scheme to give me that effect!).

4.The small packet of text is then sent somewhere else, to start an exciting adventure.

Now this is an easy scenario, and anyone can write this up, in their spare time. I just wrote it up myself in multiple programming languages using WinForms, because I was bored and had never tried it before. And with text in multiple actual languages because I am wired that way and have more keyboard layouts than possibly anyone in the entire freaking universe.

I even named the form Magic Carpet Ride, to help ameliorate the boredom.

This did not work, for what it's worth.

So instead, I entered the following 20 characters into my Magic Carpet Ride form:


Uh oh.

That last character is U+20000, the first Extension B ideograph of Unicode (aka U+d840 U+dc00, to its close friends who he is not ashamed to be disrobed, as it were, in front of)....

enter image description here

And now we have a ball game.

Because when TextBox.MaxLength talks about

Gets or sets the maximum number of characters that can be manually entered into the text box.

what it really means is

Gets or sets the maximum number of UTF-16 LE code units that can be manually entered into the text box and will mercilessly truncate the living crap out of any string that tries to play cutesy games with the linguistic character notion that only someone as obsessed as that Kaplan fellow will find offensive (geez he needs to get out more!).

I'll try and see about getting the document updated....
Regular readers who remember my UCS-2 to UTF-16 series will note my unhappiness with the simplistic notion of TextBox.MaxLength and how it should handle at a minimum this case where its draconian behavior creates an illegal sequence, one that other parts of the .Net Framework may throw a

  • System.Text.EncoderFallbackException: Unable to translate Unicode character \uD850 at index 0 to specified code page.*

exception if you pass this string elsewhere in the .Net Framework (as my colleague Dan Thompson was doing).

Now okay, perhaps the full UCS-2 to UTF-16 series is out of the reach of many.
But isn't it reasonable to expect that TextBox.Text will not produce a System.String that won't cause another piece of the .Net Framework to throw? I mean, it isn't like there is a chance in the form of some event on the control that tells you of the upcoming truncation where you can easily add the smarter validation -- validation that the control itself does not mind doing. I would go so far as to say that this punk control is breaking a safety contract that could even lead to security problems if you can class causing unexpected exceptions to terminate an application as a crude sort of denial of service. Why should any WinForms process or method or algorithm or technique produce invalid results?

Source : Michael S. Kaplan MSDN Blog

share|improve this answer
show 1 more comment

I wouldn't necessarily say that UTF-16 is harmful. It's not elegant, but it serves its purpose of backwards compatibility with UCS-2, just like GB18030 does with GB2312, and UTF-8 does with ASCII.

But making a fundamental change to the structure of Unicode in midstream, after Microsoft and Sun had built huge APIs around 16-bit characters, was harmful. The failure to spread awareness of the change was more harmful.

share|improve this answer
UTF-8 is a superset of ASCII, but UTF-16 is NOT a superset of UCS-2. Although almost a superset, a correct encoding of UCS-2 into UTF-8 results in the abomination known as CESU-8; UCS-2 doesn't have surrogates, just ordinary code points, so they must be translated as such. The real advantage of UTF-16 is that it's easier to upgrade a UCS-2 codebase than a complete rewrite for UTF-8. Funny, huh? –  Rhamphoryncus Aug 6 '10 at 7:28
Doesn't matter. Any processing other than blindly passing through the bytestream requires you to decode the surrogate pairs, which you can't do if you're treating it as UCS-2. –  Rhamphoryncus Aug 29 '10 at 13:02
show 1 more comment

Since I cannot yet comment, I post this as an answer, since it seems I cannot otherwise contact the authors of utf8everywhere.org. It's a shame I don't automatically get the comment privilege, since I have enough reputation on other stackexchanges.

This is meant as a comment to the Opinion: Yes, UTF-16 should be considered harmful answer.

One little correction:

To prevent one from accidentally passing a UTF-8 char* into ANSI-string versions of Windows-API functions, one should define UNICODE, not _UNICODE. _UNICODE maps functions like _tcslen to wcslen, not MessageBox to MessageBoxW. Instead, the UNICODE define takes care of the latter. For proof, this is from MS Visual Studio 2005's WinUser.h header:

#ifdef UNICODE
#define MessageBox  MessageBoxW
#define MessageBox  MessageBoxA
#endif // !UNICODE

At the very minimum, this error should be corrected on utf8everywhere.org.

A suggestion:

Perhaps the guide should contain an example of explicit use of the Wide-string version of a data structure, to make it less easy to miss/forget it. Using Wide-string versions of data structures on top of using Wide-string versions of functions makes it even less likely that one accidentally calls an ANSI-string version of such a function.

Example of the example:

WIN32_FIND_DATAW data; // Note the W at the end.
HANDLE hSearch = FindFirstFileW(widen("*.txt").c_str(), &data);
    MessageBoxW(nullptr, data.cFileName, nullptr, MB_OK);
share|improve this answer
show 1 more comment

I've never understood the point of UTF-16. If you want the most space-efficient representation, use UTF-8. If you want to be able to treat text as fixed-length, use UTF-32. If you want neither, use UTF-16. Worse yet, since all of the common (basic multilingual plane) characters in UTF-16 fit in a single code point, bugs that assume that UTF-16 is fixed-length will be subtle and hard to find, whereas if you try to do this with UTF-8, your code will fail fast and loudly as soon as you try to internationalize.

share|improve this answer
add comment

Someone said UCS4 and UTF-32 were same. No so, but I know what you mean. One of them is an encoding of the other, though. I wish they'd though to specify endianness from the first so we wouldn't have the endianess battle fought out here too. Couldn't they have seen that coming? At least utf-8 is the same everywhere (unless someone is following the original spec with 6-bytes). Sigh. If you use utf-16 you HAVE to include handling for multibyte chars. You can't go to the Nth character by indexing 2N into a byte array. You have to walk it, or have character indices. Otherwise you've written a bug. The current draft spec of C++ says that utf-32 and utf16 can have little-endian, big-endian, and unspecified variants. Really? If Unicode had specified that everyone had to do little-endian from the beginngin then it would have all been simpler. (I would have been fine with big-endian as well.) Instead, some people implemented it one way, some the other, and now we're stuck with silliness for nothing. Sometimes it's embarrassing to be a software engineer.

share|improve this answer
@Tronic: Technically, this is not true. Although UCS-4 can store any 32-bit integer, UTF-32 is forbidden from storing the non-character code points that are illegal for interchange, such as 0xFFFF, 0xFFFE, and the all the surrogates. UTF is a transport encoding, not an internal one. –  tchrist Aug 11 '11 at 14:30
show 2 more comments

UTF-16 is the best compromise between handling and space and that's why most major platforms (Win32, Java, .NET) use it for internal representation of strings.

share|improve this answer
-1 because UTF-8 is likely to be smaller or not significantly different. For certain Asian scripts UTF-8 is three bytes per glyph while UTF-16 is only two, but this is balanced by UTF-8 being only one byte for ASCII (which does often appear even within asian languages in product names, commands and such things). Further, in the said languages, a glyph conveys more information than a latin character so it is justified for it to take more space. –  Tronic Mar 18 '10 at 2:47
I would not call combining the worst sides of both options a good compromise. –  Tronic Mar 23 '10 at 15:36
It's not easier than UTF-8. It's variable-length too. –  luiscubal Mar 25 '10 at 17:50
Leaving debates about the benefits of UTF-16 aside: What you cited is not the reason for Windows, Java or .NET using UTF-16. Windows and Java date back to a time where Unicode was a 16-bit encoding. UCS-2 was a reasonable choice back then. When Unicode became a 21-bit encoding migrating to UTF-16 was the best choice existing platforms had. That had nothing to do with ease of handling or space compromises. It's just a matter of legacy. –  Joey Apr 2 '10 at 14:13
.NET inherits the Windows legacy here. –  Joey Apr 2 '10 at 16:19
show 8 more comments

I don't think it's harmful if the developer is careful enough.
And they should accept this trade off if they know well too.

As a Japanese software developer, I find UCS-2 large enough and limiting the space apparently simplifies the logic and reduces runtime memory, so using utf-16 under UCS-2 limitation is good enough.

There are filesystem or other application which assumes codepoints and bytes to be proportional, so that raw codepoint number can be guaranteed to be fit to some fixed size storage.

One example is NTFS and VFAT specifying UCS-2 as their filename storage encoding.

If those example really wants to extend to support UCS-4, I could agree using utf-8 for everything anyway, but fixed length has good points like:

  1. can guarantee the size by length (data size and codepoint length is proportional)
  2. can use the encoding number for hash lookup
  3. non-compressed data is reasonably sized (compared to utf-32/UCS-4)

In the future when memory/processing power is cheap even in any embeded devices, we may accept the device being a bit slow for extra cache misses or page faults and extra memory usage, but this wont happen in the near future I guess...

share|improve this answer
For those reading this comment, its worth noting that UCS-2 is not the same thing as UTF-16. Please look up the differences to understand. –  mikebabcock Dec 19 '12 at 19:39
add comment

"Should one of the most popular encodings, UTF-16, be considered harmful?"

Quite possibly, but the alternatives should not necessarily be viewed as being much better.

The fundamental issue is that there are many different concepts about: glyphs, characters, codepoints and byte sequences. The mapping between each of these is non-trivial, even with the aid of a normalization library. (For example, some characters in European languages that are written with a Latin-based script are not written with a single Unicode codepoint. And that's at the simpler end of the complexity!) What this means is that to get everything correct is quite amazingly difficult; bizarre bugs are to be expected (and instead of just moaning about them here, tell the maintainers of the software concerned).

The only way in which UTF-16 can be considered to be harmful as opposed to, say, UTF-8 is that it has a different way of encoding code points outside the BMP (as a pair of surrogates). If code is wishing to access or iterate by code point, that means it needs to be aware of the difference. OTOH, it does mean that a substantial body of existing code that assumes "characters" can always be fit into a two-byte quantity — a fairly common, if wrong, assumption — can at least continue to work without rebuilding it all. In other words, at least you get to see those characters that aren't being handled right!

I'd turn your question on its head and say that the whole damn shebang of Unicode should be considered harmful and everyone ought to use an 8-bit encoding, except I've seen (over the past 20 years) where that leads: horrible confusion over the various ISO 8859 encodings, plus the whole set of ones used for Cyrillic, and the EBCDIC suite, and… well, Unicode for all its faults beats that. If only it wasn't such a nasty compromise between different countries' misunderstandings.

share|improve this answer
The fundamental issue is that text is deceptively hard. No approach to representing that information in a digital way can be uncomplicated. It's the same reason that dates are hard, calendars are hard, time is hard, personal names are hard, postal addresses are hard: whenever digital machines intersect with human cultural constructs, complexity erupts. It’s a fact of life. Humans do not function on digital logic. –  Aristotle Pagaltzis May 7 '12 at 1:16
show 1 more comment

My guesses as to the why the Windows API (and presumably the Qt libraries) use UTF-16:

  • UTF-8 wasn't around when these APIs were being developed.
  • The OS needs to do a lookup on the code points to display the glyphs-- if the data is passed around internally as UTF-8, every time it needs to do that for a multibyte character, it would have to convert from UTF-8 to UTF-16/32. If the bytestream is stored as "wide" chars in memory, it won't need to do this conversion. So increased memory usage is a tradeoff for decreased conversion work and complexity.

When writing to a stream, however, it's considered best practice to use UTF-8 for the reasons outlined in the Joel article referenced above.

share|improve this answer
Actually UTF-8 was before utf-16 developed. At the begining there was UCS-2 because at these days unicode code point was at most 16 bits –  Artyom Jun 27 '09 at 7:53
Actually UTF-8 was around before these APIs were developed too - it was invented in 1992. The very first OS to implement any sort of UCS/Unicode support was Plan9, and it used UTF-8. –  R.. Oct 3 '10 at 16:19
show 1 more comment

This totally depends on your application. For most people, UTF-16BE is a good compromise. Other choices are either too expensive to find characters (UTF-8) or waste too much space (UTF-32 or UCS-4, where each character takes 4 bytes).

With UTF-16BE, you can treat it as UCS-2 (fixed length) in most cases. Characters beyond BMP are rare in normal applications. You still have the option to handle surrogate pair if you choose to, say you are writing an archaeology application.

share|improve this answer
With all widely-used processor architectures being LE (x86, x86-64, IA-64, ARM, etc.), using UTF-16BE would be masochism. –  Mircea Chirea Mar 17 '10 at 14:35
Why is it "too expensive" to find characters? –  luiscubal Mar 25 '10 at 17:51
This is all a myth. It is not "too expensive to find characters" in UTF-8. Virtually all string processing is sequential, not random. We lived with O(N) strlen in C forever. This is no hardship at all. –  tchrist Aug 11 '11 at 14:35
@tchrist: Yes, and it sucked there too stackoverflow.com/questions/4418708/… (Note that I am in agreement with you that UTF-8 is better; but completely ignoring the time argument is silly IMHO) –  Billy ONeal Apr 27 '12 at 16:02
show 1 more comment

protected by gnat Mar 25 at 11:35

Thank you for your interest in this question. Because it has attracted low-quality answers, posting an answer now requires 10 reputation on this site.

Would you like to answer one of these unanswered questions instead?

Not the answer you're looking for? Browse other questions tagged or ask your own question.