Unicode идентификаторы и исходный код в C ++ 11? - PullRequest
12 голосов
/ 15 апреля 2011

Я нахожу в новом стандарте C ++

2.11 Identifiers                  [lex.name]
identifier:
    identifier-nondigit
    identifier identifier-nondigit
    identifier digit
identifier-nondigit:
    nondigit
    universal-character-name
    other implementation-defined character

с дополнительным текстом

Идентификатор - это произвольно длинная последовательность букв и цифр. Каждое универсальное имя символа в идентификаторе должно обозначать символ, кодировка которого в ISO 10646 попадает в один из указанных диапазонов в E.1. [...]

Я не могу понять, что это значит. От старого стандарта я привык к тому, что "универсальное имя символа" написано, например, \u89ab. Но используя их в идентификаторе ...? Действительно?

Является ли новый стандарт более открытым по отношению к Unicode? И я не имею в виду новые литеральные типы "uHello \u89ab thing"u32, мне кажется, я их понял. Но:

  • Может ли (переносимый) исходный код быть в любой кодировке Unicode, например, UTF-8, UTF-16 или любой (как определено) кодовой странице?
  • Могу ли я написать идентификатор с \u1234 в нем myfu\u1234ntion (для любых целей)
  • Или я могу использовать "имена символов", которые Unicode определяет как в ICU, т.е.

    const auto x = "German Braunb\U{LOWERCASE LETTER A WITH DIARESIS}r."u32;
    

    или даже в идентификаторе в самом источнике? Это было бы удовольствием ... кашель ...

Я думаю, что ответ на все эти вопросы нет , но я не могу надежно сопоставить это с формулировкой в ​​стандарте ...: -)

Редактировать: Я нашел "2.2 Фазы перевода [lex.phases]", Фаза 1:

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

Читая это, я теперь думаю, что компилятор может принять UTF-8, UTF-16 или любую другую кодовую страницу, которую он пожелает (по метаинформации или конфигурации пользователя). На этапе 1 он преобразует это в форму ASCII («базовый исходный набор символов»), в которой символы Unicode заменяются его нотацией \uNNNN (или компилятор может продолжить работу в своем представлении Unicode, но чем убедиться, что он обрабатывает другой \uNNNN таким же образом.

Что вы думаете?

Ответы [ 5 ]

12 голосов
/ 02 июля 2013

Является ли новый стандарт более открытым по отношению к Unicode?

Что касается разрешения универсальных имен символов в идентификаторах, ответ - нет;UCN были разрешены в идентификаторах еще в C99 и C ++ 98.Однако компиляторы не выполняли это конкретное требование до недавнего времени.Clang 3.3 Я думаю, что вводит поддержку этого, и у GCC была экспериментальная функция для этого в течение некоторого времениХерб Саттер также упомянул в своем выступлении на Build 2013 «Будущее C ++», что эта функция также появится в VC ++ в какой-то момент.(Хотя IIRC Herb называет его функцией C ++ 11; на самом деле это функция C ++ 98.)

Не ожидается, что идентификаторы будут записываться с использованием UCN.Вместо этого ожидаемое поведение заключается в написании нужного символа с использованием исходной кодировки.Например, источник будет выглядеть так:

long pörk;

not:

long p\u00F6rk;

Однако UCN также полезны для другой цели;Не все компиляторы обязаны принимать одинаковые исходные кодировки, но все современные компиляторы поддерживают некоторую схему кодирования, в которой по крайней мере базовые исходные символы имеют одинаковую кодировку (то есть все современные компиляторы поддерживают некоторую ASCII-совместимую кодировку).

UCN позволяют вам писать исходный код только с основными символами и все же называть расширенные символы.Это полезно, например, при записи строкового литерала «°» в исходном коде, который будет скомпилирован как CP1252 и как UTF-8:

char const *degree_sign = "\u00b0";

Этот строковый литерал кодируется в соответствующую кодировку выполненияна нескольких компиляторах, даже если исходные кодировки различаются, при условии, что компиляторы, по крайней мере, используют одну и ту же кодировку для основных символов.

Может ли (переносимый) исходный код быть в любой кодировке Unicode, например UTF-8, UTF-16 или любая (как когда-либо определенная) кодовая страница?

Стандарт не требуется, но большинство компиляторов принимают исходный код UTF-8.Clang поддерживает только источник UTF-8 (хотя он имеет некоторую совместимость для данных не-UTF-8 в символьных и строковых литералах), gcc позволяет указывать кодировку источника и включает поддержку UTF-8, иVC ++ будет угадывать кодировку и может быть угадан в UTF-8.

(Обновление: VS2015 теперь предоставляет опцию , чтобы исходные и исполнительные наборы символов были UTF-8.)

Могу ли я написать идентификатор с \ u1234 в нем myfu \ u1234ntion (для любых целей)

Да, спецификация обязывает это, хотя, как я уже сказал, не всекомпиляторы реализуют это требование.

Или я могу использовать "имена символов", которые Unicode определяет, как в ICU, то есть

const auto x = "German Braunb\U{LOWERCASE LETTER A WITH DIARESIS}r."u32;

Нет, вы не можете использоватьЮникод длинных имен.

или даже в идентификаторе в самом источнике?Это было бы угощением ... кашель ...

Если компилятор поддерживает кодировку исходного кода, которая содержит расширенный символ, который вы хотите, то этот символ, записанный буквально в источнике, должен обрабатываться точно так жев качестве эквивалента UCN.Так что да, если вы используете компилятор, который поддерживает это требование спецификации C ++, тогда вы можете написать любой символ в его исходном наборе символов непосредственно в источнике, не беспокоясь о написании UCN.

2 голосов
/ 25 сентября 2016

Я предлагаю использовать clang++ вместо g++. Clang разработан для обеспечения высокой совместимости с GCC ( wikipedia-source ), поэтому вы, скорее всего, можете просто заменить эту команду.

Я хотел использовать греческие символы в моем исходном коде. Если целью является читабельность кода, то разумно использовать (например) α вместо alpha. Особенно при использовании в больших математических формулах, их легче читать в исходном коде.

Чтобы достичь этого, это минимальный рабочий пример:

> cat /tmp/test.cpp
#include <iostream>

int main()
{
    int α = 10;
    std::cout << "α = " << α << std::endl;
    return 0;
}
> clang++ /tmp/test.cpp -o /tmp/test
> /tmp/test 
α = 10
2 голосов
/ 15 апреля 2011

Я думаю, что цель состоит в том, чтобы разрешить символы Unicode в идентификаторах, таких как:

long pöjk;
ostream* å;
1 голос
/ 15 августа 2015

Существующие версии gcc (до версии 5.2) поддерживают только ASCII и в некоторых случаях входные файлы EBCDIC.Поэтому символы Unicode в идентификаторах должны быть представлены с помощью escape-последовательностей \ uXXXX и \ UXXXXXXXX в файлах, закодированных в ASCII.Хотя может быть возможно представить символы Юникода как ?? / uXXXX и ?? / UXXXXXXX в кодированных входных файлах EBCDIC, я не проверял это.В любом случае, простой однострочный патч для cpp позволяет напрямую читать ввод UTF-8, если установлена ​​последняя версия iconv.Подробности в

https://www.raspberrypi.org/forums/viewtopic.php?p=802657

и могут быть обобщены патчем

diff -cNr gcc-5.2.0/libcpp/charset.c gcc-5.2.0-ejo/libcpp/charset.c
*** gcc-5.2.0/libcpp/charset.c  Mon Jan  5 04:33:28 2015
--- gcc-5.2.0-ejo/libcpp/charset.c  Wed Aug 12 14:34:23 2015
***************
*** 1711,1717 ****
    struct _cpp_strbuf to;
    unsigned char *buffer;

!   input_cset = init_iconv_desc (pfile, SOURCE_CHARSET, input_charset);
    if (input_cset.func == convert_no_conversion)
      {
        to.text = input;
--- 1711,1717 ----
    struct _cpp_strbuf to;
    unsigned char *buffer;

!   input_cset = init_iconv_desc (pfile, "C99", input_charset);
    if (input_cset.func == convert_no_conversion)
      {
        to.text = input;
1 голос
/ 02 августа 2011

Эта статья https://www.securecoding.cert.org/confluence/display/seccode/PRE30-C.+Do+not+create+a+universal+character+name+through+concatenation работает с идеей, что int \u0401; является совместимым кодом, хотя он основан на C99, а не на C ++ 0x.

...