It is a common practice in C to use arrays of
char as strings. The 0 is used as end marker.
The whole thing was created like that in the 1970s and at that time it was kind of cool to get away with one less language feature and to express it in terms of others instead. And people did not think enough about the necessity to express more than ISO 646 IRV (commonly called ASCII) as string content.
This extended out of the box to 8 bit character sets like ISO 8859-1 or KOI-8, that are identical to ISO 646 in the lower 128 characters and contain an extension in the upper 128 characters. But fortunately we have moved ahead and now Unicode with its encodings UTF-8, UTF-16 and UTF-32.
How can we deal with this in C?
UTF-8 just works out of the box, because the byte 0 is only used to encode the code point U+0000. So the null termination can be kept as it is and a lot of functionality remains valid. Some issues arise, because in UTF-8 things like finding the logical length of a string, not its memory consumption or finding the nth code point, not the nth byte, require UTF-8-logic to be applied and to parse the whole string at least from the beginning to the desired position or the usage of an indexing facility. So a lot of non-trivial string functionality of the standard library will just not be as easy as people thought it would be in the 1970s and subsequently not work as needed. Libraries for better UTF-8-support in C can be found, leaving the „native“ C strings with UTF-8 content only for usage in interfaces that require them. I have not yet explored such libraries, but it would be interesting to find out how powerful and useful they are.
At the time when Unicode came out, it seemed to be sufficient to have 16 bits per character instead of 8. Java was built on this assumption. C added a wchar_t to allow for this and just required it to be „long enough“. So Linux uses 32 bits and MS-Windows 16 bits. This is not too bad, because programming in C for MS-Windows and for Linux is anyway quite different, unless we abstract the differences into a library, which would then also include a common string definition and string handling functionality. While the Linux wchar_t is sufficient, it really wastes a lot of memory, which is often undesirable, if we go the extra effort to program in C in order to gain performance. The Windows-wchar_t is „kind of sufficient“, as are the Java-Strings, because we can really do a lot with assuming that Unicode is only 16 bit or with UTF-16 and ignoring the complexities of that, that are in principal the same as for UTF-8, but can be ignored with less disadvantages most of the time. The good news is, that wchar_t is well supported by standard library functions.
Another way is to use char16_t and char32_t, that have a clear definition of their length, but much less library support.
Probably these facilities are sufficient for software whose string handling is relatively trivial. For more ambitious string handling in terms of functionality and performance, it will be necessary to find third party libraries or to write them.
- Unicode in C and C++: What You Can Do About It Today
- What every programmer absolutely, positively needs to know about encodings and character sets to work with text
- Wikipedia: Comparison of Unicode encodings
- Wikipedia: Unicode
- Wikipedia: UTF-8
- Wikipedia: UTF-16
- Wikipedia: UTF-32
- Wikipedia: GB 18030
- Wikipedia: ISO 8859-1
- Wikipedia: ISO 8859-15
- Wikipedia: BOCU
- Wikipedia: SCSU
- Unicode, UTF-8, UTF-16, ISO-8859-1: Why is it so difficult?
- Introduction to Unicode and UTF-8
- UTF-8 everywhere
- UTF-8 and Unicode FAQ for Unix/Linux
- docs.microsoft.com: char, wchar_t, char16_t, char32_t
- cplusplus.com: wchar_t
- Programming in Linux
- Для чего нужен тип `wchar_t`?
- Wikipedia: GLib