===== C/C++ UTF chaos ===== ==== MSVC, кодировка исходников и строковые литералы ==== MSVC предоставляет аж 5 (прописью: пять) вариантов кодировки UTF для сохранения исходников: * Нормальный человеческий UTF-8 * UTF-8, но с BOM (byte order mark, который в случае UTF-8 [[https://stackoverflow.com/a/2223926|не рекомендован]] к применению стандартом Unicode, от него одна головная боль) * Редкий зверь UTF-7 (он где-то кроме IMAP встречается?) * UTF-16 LE * UTF-16 BE Сохранение исходников любом UTF, кроме UTF-8, не кросс-платформенно и поэтому не рассматривается. Остаются UTF-8 с и без BOM. В коде литералы строк могут быть "однобайтные" (char) и "широкие" (wchar_t): const char* cs = "Я"; const wchar_t* ws = L"Я"; Символ 'Я' в UTF-8 представляется как ''D0 AF'', а в UTF-16 -- как ''042F''. ^Литерал ^На диске ^В памяти ^^ ^::: ^::: ^BOM ^Без BOM ^ |''char*'' |''D0 AF'' |''DF 00'' |''D0 AF 00'' | |''wchar_t*'' |::: |''042F 0000'' |''0420 0407 0000'' | '' '' В случае с BOM, в ''char*'' один символ ''DF'' -- это 'Я' в Windows-1251, т. е. MSVC конвертирует строку в системную ANSI-кодировку (очевидно, с потерями). Зато с ''wchar_t*'' все в порядке. Без BOM наоборот, в ''char*'' записано желаемое UTF-8 представление строки, но вот в ''wchar_t*'' -- непонятные ''0420 0407''. Это UTF-16 представление символов ''РЇ'', которые в Windows-1251 имеют коды ''D0 AF'' (сравните с исходным UTF-8). То есть, корректность обработки юникодных строковых литералов зависит от параметров сохранения файла, а одновременное использование ''char*'' и ''wchar_t*'' в этом случае и вовсе невозможно: * При сохранении исходника в UTF-8 с BOM, будут испорчены ''char*'' (сконвертированы в "системный" ANSI). * При сохранении в UTF-8 без BOM, будут испорчены ''wchar_t*'' (сконвертированы в UTF-16, как будто исходник был в ANSI).