Ответ 1
Основная проблема с использованием символов, отличных от ASCII в источнике С++, заключается в том, что компилятор должен знать кодировку, используемую для источника. Если источником является 7-разрядный ASCII, это обычно не имеет значения, так как большинство всех компиляторов по умолчанию используют кодировку, совместимую с ASCII.
Также не все компиляторы конфигурируются относительно кодировки, поэтому два компилятора могут безоговорочно использовать несовместимые кодировки, а это означает, что использование символов, отличных от ASCII, может привести к исходному коду, который нельзя использовать с обоими.
- GCC: имеет параметры командной строки для установки кодировки источника, исполнения и широкого исполнения. По умолчанию устанавливаются локаль, которая обычно использует UTF-8 в эти дни.
- MSVC: использует так называемую "спецификацию" для определения исходной кодировки (между UTF-16BE/LE, UTF-8 и кодировкой языковой системы) и всегда использует языковой стандарт системы в качестве исполнения. edit: Начиная с версии VS 2015 Update 2, MSVC поддерживает компиляторы для управления кодировками источника и исполнения, включая поддержку UTF-8. см. здесь
- Clang: всегда использует UTF-8 в качестве кодировки источника и исполнения
Итак, подумайте, что происходит с вашим кодом для поиска акцентированного символа, если искомая строка является UTF-8 (возможно, потому, что набор символов выполнения - UTF-8). Является ли символьный литерал "é" работает так, как вы ожидаете, или нет, вы не будете находить акцентированные символы, потому что акцентированные символы не будут представлены ни одним байтом. Вместо этого вам придется искать различные байтовые последовательности.
Существуют разные типы экранов, которые С++ допускает в символьных и строковых литералах. Универсальные имена символов позволяют назначать кодовую точку Юникода и обрабатываться точно так, как если бы этот символ появился в источнике. Например \u00E9
или \U000000E9
.
(некоторые другие языки имеют \u
для поддержки кодовых точек до U + FFFF, но не имеют поддержки С++ для кодовых точек, выходящих за рамки этого, или для использования суррогатных кодовых точек. Вы не можете использовать суррогатные коды в С++, а вместо этого С++ имеет вариант \U для поддержки всех кодовых точек непосредственно.)
UCN также должны работать вне символов и строковых литералов. Вне таких литералов UCN ограничиваются символами, не содержащими базовый набор символов. Однако до недавнего времени компиляторы не реализовали эту функцию (С++ 98). Теперь у Clang появилась довольно полная поддержка, MSVC, похоже, имеет хотя бы частичную поддержку, и GCC хочет предоставить экспериментальную поддержку с опцией -fextended-identifiers
.
Напомним, что UCN должны рассматриваться одинаково с фактическим символом, появляющимся в источнике; Таким образом, компиляторы с хорошей поддержкой идентификатора UCN также позволяют просто писать идентификаторы с использованием фактического символа, пока кодирование исходного кода компилятора поддерживает символ в первую очередь.
С++ также поддерживает шестнадцатеричные экраны. Это \x, за которым следует любое число шестнадцатеричных цифр. Выражение hex будет представлять собой единое целочисленное значение, как если бы это был единственный код с этим значением, и никакое преобразование в кодировку выполнения не выполняется по значению. Если вам нужно представить конкретное значение байта (или char16_t или char32_t или wchar_t), не зависящее от кодировок, то это то, что вы хотите.
Есть также восьмеричные escape-последовательности, но они не так часто полезны, как UCN или шестнадцатеричные escape-последовательности.
Здесь диагноз, который показывает Clang, когда вы используете 'é' в исходном файле, закодированном с ISO-8859-1 или cp1252:
warning: illegal character encoding in character literal [-Winvalid-source-encoding]
std::printf("%c\n",'<E9>');
^
Clang выдает это только как предупреждение и просто выведет объект char с исходным байтовым значением. Это делается для обратной совместимости с исходным кодом, отличным от UTF-8.
Если вы используете кодированный источник UTF-8, вы получите следующее:
error: character too large for enclosing character literal type
std::printf("%c\n",'<U+00E9>');
^
Clang обнаруживает, что кодировка UTF-8 соответствует кодовой точке Unicode U + 00E9 и что эта кодовая точка находится за пределами диапазона, который может содержать один char, и поэтому сообщает об ошибке. (Кланг также избегает символа не ascii, потому что он определил, что консоль, в которой он запускался, не может обрабатывать печать символа, отличного от ascii).