В сети и здесь, на SO, довольно много материала о работе с кодировками и локалями. Но почему-то нет вразумительной информации о кодировке строковых констант (литералов).
const char * text = "Какая ваша кодировка?";
Чем определяется кодировка строковых литералов: кодировкой файла с исходником, опциями компилятора или чем-то еще? Что на эту тему говорит стандарт? Как достоверно узнать кодировку строковых литералов на этапе компиляции (может макросы какие есть)? А в рантайме?
Ответ
Данный ответ посвящён практике применения Microsoft Visual Studio.
Хорошего кроссплатформенного решения я, к сожалению, не знаю.
Для файлов-исходников в неюникодных кодировках, строка интерпретируется как строка в ANSI-кодировке. Для русскоязычных систем это CP 1251. Это выполняется даже если для файла исходника задекларирована другая кодировка! При компиляции на системе с другой ANSI-кодировкой результат будет отличаться.
Для файлов-исходников в юникодных кодировках, кодировка строки также Unicode.
Если при этом строка «узкая» (то есть, типа char[]), то строка будет сконвертирована в ANSI-кодировку с теми же последствиями.
Если при этом строка «широкая» (то есть, типа wchar_t[]), то строка останется как есть, то есть, правильной.
Это означает, что нужно использовать
либо юникодную кодировку исходников + широкие строки,
либо узкие строки в ANSI-кодировке с потерей компилируемости под нерусскими системами,
либо кодировать литералы числовыми константами.
Как выяснилось в результате длительной дискуссии с @ixSci и @Abyx, Visual Studio 2015 ведёт себя немного по-другому: в случае кодировки файла utf-8 и узкой строки, в строке таки окажется utf-8. Но в случае кодировки файла utf-16 (ucs-2), результат прежний: попытка сконвертировать в ANSI (которая может и провалиться).
Обновление:
Visual Studio 2015 и старше конвертирует строки во внутренний формат. Конвертация определяется набором символов исходного файла (source character set), из которого символы конвертируются во внутренний формат (на текущий момент это utf-8). Набор символов, т. е., по сути, кодировка исходного файла определяется следующим образом
Если файл содержит BOM, этим самым однозначно определяется его кодировка.
В противном случае, если файл выглядит как файл в utf-16 (Visual Studio производит прикидку этого по первым восьми байтам) big/little endian, то это считается его кодировкой.
В противном случае, если при компиляции (или в настройках проекта) указан ключ /source-charset, указанная в этом ключе кодировка и считается кодировкой входного файла.
В противном случае, кодировкой входного файла считается системная кодовая страница (т. е., ANSI). Обратите внимание, что это не самый лучший вариант, т. к. одни и те же байты исходников при этом могут по-разному интерпретироваться на разных системах.
Следующая важная вещь — это набор символов времени выполнения (execution character set). Это, по сути, кодировка, в которую будут сконвертированы узкие строковые/символьные литералы (объявленные без префикса) при записи в выполняемый файл, и которые программа «увидит», если просканирует строки по байтам. Если при компиляции указан ключ /execution-charset, это и будет искомым набором символов. Если нет, в качестве набора символов используется текущая кодовая страница.
Обратите внимание, что вы можете указать ключ /utf-8, который установит одним махом оба набора символов в utf-8.
Ещё один набор символов — широкий набор символов времени выполнения (wide execution character set) — используется для конвертации широких символьных/строковых литералов. Он в MS Visual Studio неизменен и совпадает с utf-16.
Документация: Visual C++ Team Blog / New Options for Managing Character Sets in the Microsoft C/C++ Compiler
Комментариев нет:
Отправить комментарий