/* * sample-utf8.c: non-ASCII text in C string literals. * Free sample from 99helpers.com/file-types/c * * Saved as UTF-8 without a byte order mark. GCC and Clang read source files * as UTF-8 by default and copy the bytes into the program unchanged. * Microsoft's compiler assumes the system code page instead, unless you add * /utf-8: * cc -Wall -Wextra -std=c17 sample-utf8.c -o sample-utf8 && ./sample-utf8 * cl /W4 /std:c17 /utf-8 sample-utf8.c * On Windows, run `chcp 65001` first so the console shows UTF-8 output. */ #include #include /* strlen counts bytes, not characters. In UTF-8 every character starts with * a byte that is not of the form 10xxxxxx, so counting those bytes counts * code points (what a reader would mostly call characters). */ static size_t utf8_length(const char *s) { size_t n = 0; for (; *s != '\0'; s++) { if (((unsigned char)*s & 0xC0) != 0x80) { n++; } } return n; } int main(void) { static const char *const greetings[] = { "Hello", /* English: 1 byte per letter */ "Grüß Gott", /* German: ü and ß take 2 bytes each */ "Bonjour, ça va ?", /* French */ "Привет", /* Russian: Cyrillic, 2 bytes each */ "Γειά σου", /* Greek */ "שלום", /* Hebrew, written right to left */ "مرحبا", /* Arabic, written right to left */ "こんにちは", /* Japanese: 3 bytes each */ "你好", /* Chinese */ "€ 12,50 · ½ · ±", /* symbols */ "👋🙂", /* emoji: 4 bytes each */ }; for (size_t i = 0; i < sizeof greetings / sizeof greetings[0]; i++) { printf("%2zu bytes, %2zu characters: %s\n", strlen(greetings[i]), utf8_length(greetings[i]), greetings[i]); } return 0; }