MSVC предоставляет аж 5 (прописью: пять) вариантов кодировки UTF для сохранения исходников:
Сохранение исходников любом 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*
в
этом случае и вовсе невозможно:
char*
(сконвертированы в “системный” ANSI).wchar_t*
(сконвертированы в UTF-16, как будто исходник был в ANSI).