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).