#cpp #c #кодировка
В сети и здесь, на SO, довольно много материала о работе с кодировками и локалями.
Но почему-то нет вразумительной информации о кодировке строковых констант (литералов).
const char * text = "Какая ваша кодировка?";
Чем определяется кодировка строковых литералов: кодировкой файла с исходником, опциями
компилятора или чем-то еще? Что на эту тему говорит стандарт? Как достоверно узнать
кодировку строковых литералов на этапе компиляции (может макросы какие есть)? А в рантайме?
Ответы
Ответ 1
Данный ответ посвящён практике применения 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.Ответ 2
Кодировка такой строки: const char * text = "Какая ваша кодировка?"; Определяется исключительно кодировкой файла, в котором содержится данное определение. Начиная с C++11 можно явно указать, что хотите видеть строку в unicode, для этого есть следующие префиксы: u(UCS-2), u8(UTF-8) и U(UCS-4). Пример: const char * text = u8"Какая ваша кодировка?"; Теперь текст гарантировано содержит строку в utf-8, вне зависимости от компилятора(если он поддерживает стандарт, разумеется) Узнать кодировку макросами или другим «волшебством», насколько я знаю, — нельзя. Обычный совет, это не использовать не-английский текст в исходниках вообще. Так будет меньше головной боли, храните текст в отдельных файлах и читайте их по мере надобности.Ответ 3
GCC имеет опции препроцессора для указания кодировок строковых констант и исходников. -fexec-charset=charset Устанавливает кодировку строковых и символьных констант исполняемого файла. По-умолчанию используется UTF-8. charset может быть именем кодировки которое поддерживается библиотекой iconv установленой в системе. -fwide-exec-charset=charset Устанавливает кодировку, "широких" строковых и символьных констант исполняемого файла. По-умолчанию используется UTF-32 или UTF-16 в зависимости от "ширины" типа wchar_t. Как и вслучае -fexec-charset, charset может быть именем кодировки которое поддерживается библиотекой iconv установленой в системе. -finput-charset=charset Указывает компилятору кодировку входных файлов. Кодировка используется для перекодирования входных файлов в кодировку используемую компилятором GCC. По-умолчанию charset равен системеной кодировке, если системная кодировка не задана или GCC не может ее получить, то в качестве charset используется UTF-8. В настоящий момент опция имеет преимущество в случае возникновения конфликтов. charset может быть именем кодировки которое поддерживается библиотекой iconv установленой в системе.
Комментариев нет:
Отправить комментарий