Почему строковый знак евро внутри строкового литерала с использованием UTF8 не создает UCN? - PullRequest
7 голосов
/ 24 июня 2011

В спецификации говорится, что на этапе 1 компиляции

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

И на этапе 4 говорится:

Выполняются директивы предварительной обработки, расширяются вызовы макросов

На этапе 5 имеем

Каждый элемент исходного набора символов в символьном литерале или строковом литерале, а также каждая escape-последовательность и универсальное имя-символа в символьном литерале или неочищенном строковом литерале преобразуется в соответствующийчлен набора символов выполнения

Для оператора # у нас есть

\ символов, вставляемых перед каждым " и \ символамисимвольного литерала или строкового литерала (включая " символов-разделителей).

Поэтому я провел следующий тест

#define GET_UCN(X) #X
GET_UCN("€")

со входным набором символов UTF-8(соответствует кодировке моего файла), я ожидал следующий результат предварительной обработки операции #X: "\"\\u20AC\"".GCC, Clang и boost.wave не преобразуют в UCN и вместо этого дают "\"€\"".Я чувствую, что что-то упустил.Не могли бы вы объяснить?

Ответы [ 4 ]

1 голос
/ 24 июня 2011

Это просто ошибка. §2.1 / 1 говорит о Фазе 1,

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

Это не примечание или сноска. C ++ 0x добавляет исключение для необработанных строковых литералов, которые могут решить вашу проблему под рукой, если у вас есть такой.

Эта программа наглядно демонстрирует неисправность:

#include <iostream>

#define GET_UCN(X) L ## #X

int main() {
std::wcout << GET_UCN("€") << '\n' << GET_UCN("\u20AC") << '\n';
}

http://ideone.com/lb9jc

Поскольку обе строки широкие, первую необходимо разбить на несколько символов, если компилятор не сможет интерпретировать входную многобайтовую последовательность. В приведенном вами примере полное отсутствие поддержки UTF-8 может привести к тому, что компилятор будет рабски повторять последовательность сразу.

0 голосов
/ 24 июня 2011

"и универсальное имя-символа в символьном литерале или строковом литерале, не являющемся необработанным, преобразуется в соответствующий член набора символов выполнения"

раньше было

"или имя универсального символа в символьных литералах и строковых литералах преобразуется в член набора символов выполнения"

Может быть, вам нужна будущая версия g ++.

0 голосов
/ 24 июня 2011

Я не уверен, откуда вы взяли эту цитату для фазы перевода 1 - стандарт C99 говорит об этой фазе перевода в §5.1.1.2 / 1:

Многобайтовые символы физического исходного файла отображаются, в зависимости от реализации, в исходный набор символов (ввод символов новой строки для индикаторов конца строки), если необходимо. Триграфные последовательности заменяются соответствующими односимвольными внутренними представлениями.

Таким образом, в этом случае символ евро € (представленный в виде многобайтовой последовательности E2 82 AC в UTF-8) отображается в набор символов выполнения, который также является UTF-8, поэтому его представление остается тем же. Он не преобразуется в универсальное имя персонажа, потому что, ну, нет ничего, что говорит, что он должен.

0 голосов
/ 24 июня 2011

Я подозреваю, вы обнаружите, что знак евро не удовлетворяет условию Any source file character not in the basic source character set, поэтому остальная часть текста, который вы цитируете, не применяется.

Откройте свой тестовый файл в своем любимом бинарном редакторе и проверьте, какое значение используется для представления знака евро в GET_UCN("€")

...