Как кодировка файла влияет на строковые литералы C ++ 11? - PullRequest
11 голосов
/ 22 июля 2011

Вы можете написать строковые литералы UTF-8/16/32 в C ++ 11, добавив к строковому литералу u8 / u / U соответственно. Как компилятор должен интерпретировать файл UTF-8, который содержит символы не ASCII внутри этих новых типов строковых литералов? Я понимаю, что стандарт не определяет кодировки файлов, и один только этот факт сделает интерпретацию не-ASCII-символов внутри исходного кода совершенно неопределенным поведением, сделав эту функцию чуть менее полезной.

Я понимаю, что вы все еще можете экранировать одиночные символы Юникода с помощью \uNNNN, но это не очень хорошо читается, скажем, для полного русского или французского предложения, которое обычно содержит более одного символа Юникода.

Из различных источников я понимаю, что u должно стать эквивалентным L в текущих реализациях Windows и U, например, в. Реализации Linux. Поэтому, учитывая это, мне также интересно, какое поведение требуется для старых строковых литеральных модификаторов ...

Для примера кода обезьян:

string utf8string a = u8"L'hôtel de ville doit être là-bas. Ça c'est un fait!";
string utf16string b = u"L'hôtel de ville doit être là-bas. Ça c'est un fait!";
string utf32string c = U"L'hôtel de ville doit être là-bas. Ça c'est un fait!";

В идеальном мире все эти строки производят одинаковое содержимое (как в: символы после преобразования), но мой опыт работы с C ++ научил меня, что это определенно определенная реализация и, вероятно, только первая будет делать то, что я хочу ,

Ответы [ 3 ]

8 голосов
/ 22 июля 2011

В GCC используйте -finput-charset=charset:

Установите набор символов ввода, используемый для перевода из набора символов входного файла в исходный набор символов, используемый GCC. Если языковой стандарт не указан или GCC не может получить эту информацию из языкового стандарта, по умолчанию используется UTF-8. Это может быть отменено либо локалью, либо параметром командной строки. В настоящее время параметр командной строки имеет приоритет, если есть конфликт. charset может быть любой кодировкой, поддерживаемой системной библиотечной программой "iconv".

Также проверьте опции -fexec-charset и -fwide-exec-charset.

Наконец, о строковых литералах:

char     a[] = "Hello";
wchar_t  b[] = L"Hello";
char16_t c[] = u"Hello";
char32_t d[] = U"Hello";

Модификатор размера строкового литерала (L, u, U) просто определяет тип литерала.

5 голосов
/ 23 июля 2011

Как компилятор должен интерпретировать файл UTF-8, который содержит символы не ASCII внутри этих новых типов строковых литералов.Я понимаю, что стандарт не определяет кодировки файлов, и один только этот факт сделает интерпретацию не-ASCII-символов внутри исходного кода совершенно неопределенным поведением, сделав эту функцию чуть менее полезной.

От n3290, 2.2 Фазы перевода [lex.phases]

Физические символы исходного файла отображаются, в соответствии с реализацией, в базовый исходный набор символов (введение символов новой строки для конца строки).линейные индикаторы) при необходимости.Допустимый набор физических символов исходного файла определяется реализацией.[ Вот немного о триграфах. ] Любой символ исходного файла, не входящий в базовый набор символов источника (2.3), заменяется универсальным именем символа, которое обозначает этот символ.(Реализация может использовать любую внутреннюю кодировку, если фактический расширенный символ, встречающийся в исходном файле, и тот же расширенный символ, выраженный в исходном файле, что и имя универсального символа (т. Е. С использованием нотации \ uXXXX),обрабатывается эквивалентно, за исключением случаев, когда эта замена возвращается в виде необработанного строкового литерала.)

Существует множество стандартных терминов, используемых для описания того, как реализация работает с кодировками.Вот моя попытка сделать несколько более простое, пошаговое описание того, что происходит:

Физические символы исходного файла отображаются, в соответствии с реализацией, в основной исходный набор символов [...]

Проблема кодирования файлов решена вручную;Стандарт заботится только об основном исходном наборе символов и оставляет место для реализации, чтобы туда добраться.

Любой символ исходного файла, не входящий в базовый исходный набор символов (2.3), заменяется универсальным символом-имя, обозначающее этот символ.

Основной исходный набор представляет собой простой список разрешенных символов. Это не ASCII (см. Далее).Все, чего нет в этом списке, «преобразуется» (по крайней мере, концептуально) в форму \uXXXX.

Поэтому, независимо от того, какой тип литерала или кодировки файла используется, исходный код концептуально преобразуется в базовый символкомплект + куча \uXXXX.Я говорю концептуально, потому что то, что фактически делают реализации, обычно проще, например, потому что они могут иметь дело с Unicode напрямую.Важной частью является то, что то, что Стандарт называет расширенным символом (то есть не из базового исходного набора), должно быть неотличимо в использовании от его эквивалентной формы \uXXXX.Обратите внимание, что C ++ 03 доступен, например, на платформах EBCDIC, поэтому ваши рассуждения с точки зрения ASCII ошибочны с самого начала.

Наконец, описанный мной процесс также происходит с (не необработанными) строковыми литералами.Это означает, что ваш код эквивалентен, как если бы вы написали:

string utf8string a = u8"L'h\u00F4tel de ville doit \u00EAtre l\u00E0-bas. \u00C7a c'est un fait!";
string utf16string b = u"L'h\u00F4tel de ville doit \u00EAtre l\u00E0-bas. \u00C7a c'est un fait!";
string utf32string c = U"L'h\u00F4tel de ville doit \u00EAtre l\u00E0-bas. \u00C7a c'est un fait!";
0 голосов
/ 10 октября 2015

В принципе, вопросы кодирования имеют значение только тогда, когда вы выводите свои строки, делая их видимыми для людей, что не является вопросом определения языка программирования, поскольку его определение касается только вычислений кодирования.Итак, когда вы решаете, будет ли то, что вы видите в своем редакторе, таким же, как то, что вы видите в выводе (любые виды изображений, будь то на экране или в формате PDF), вы должны спросить себя, какое соглашениеспособ кодирования библиотеки взаимодействия с пользователем и операционной системы.(Вот, например, такая информация для Qt5 : с Qt5 то, что вы видите как пользователь приложения, и то, что вы видите как его программист, совпадает, если содержимое старомодной строкилитералы для ваших QStrings кодируются как utf8 в ваших исходных файлах, если вы не включите другую настройку в ходе выполнения приложения).

В заключение я считаю, что Kerrek SB прав, а Дэймон неправ:действительно, методы указания литерала в коде должны указывать его тип, а не кодировку, которая используется в исходном файле для заполнения его содержимого, так как тип литерала - это то, что касается вычислений, выполненных с ним.Что-то вроде u"string" - это просто массив «юникод-кодовых блоков» (то есть значений типа char16_t), независимо от того, что операционная система или любое другое служебное программное обеспечение впоследствии делает с ними, и, тем не менее, их работа ищет вас или другого пользователя.,Вы просто попадаете на проблему добавления другого соглашения для себя, которое устанавливает соответствие между «значением» вычисляемых чисел (а именно, они представляют коды Unicode) и их представлением на экране, когда вы работаете в текстовом редакторе.,Как и если вы, как программист, используете это «значение», это другой вопрос, и как вы могли бы обеспечить выполнение этой другой корреспонденции, естественно, будет зависеть от реализации, потому что она не имеет ничего общего с вычислениями кода, только с удобством использования инструмента.

...