С11 Сборник. Этап перевода № 1 и № 5. Универсальные имена персонажей

Я пытаюсь понять универсальные имена символов в стандарте C11 и обнаружил, что черновик N1570 стандарта C11 содержит гораздо меньше деталей, чем стандарт C ++ 11, в отношении этапов перевода 1 и 5 и формирования и обработки UCN в пределах их. Это то, что каждый должен сказать:

Этап перевода 1

N1570 Проект C11 5.1.1.2p1.1:

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

C ++ 11 2.2p1.1:

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

Этап перевода 5

N1570 Проект C11 5.1.1.2p1.5:

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

C ++ 2.2p1.5:

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

(акцент был добавлен на различия)

Вопросы

  1. В стандарте C ++ 11 совершенно ясно, что символы исходного файла, не входящие в базовый исходный набор символов, преобразуются в UCN, и что они обрабатываются точно так же, как и UCN в том же месте, за единственным исключением: Сыра-строка. То же самое относится и к С11? Когда компилятор C11 видит многобайтовый символ UTF-8, такой как °переводит ли это слишком \u00b0 в фазе 1, и относиться к нему так же, как если бы \u00b0 появился там вместо этого?

  2. Иными словами, в конце какой фазы перевода, если таковые имеются, следующие фрагменты кода преобразуются в текстуально эквивалентный формы впервые в С11?

    const char* hell° = "hell°";
    

    а также

    const char* hell\u00b0 = "hell\u00b0";
    
  3. Если в 2. ответ «нет», то на каком этапе перевода эти два идентификатора сначала понимаются как относящиеся к одной и той же вещи, несмотря на то, что они различаются по тексту?

  4. В C11 UCN в символьных / строковых литералах также преобразуются в фазе 5? Если это так, то почему бы исключить это из проекта стандарта?
  5. Как обрабатываются UCN в идентификаторах (в отличие от символьных / строковых литералов, как уже упоминалось) в C11 и C ++ 11? Они также преобразованы в фазе 5? Или это что-то определенное реализацией? Распечатывает ли, например, GCC такие идентификаторы в кодированной форме UCN или в фактическом UTF-8?

4

Решение

Комментарии превратились в ответ

Интересный вопрос!

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

  1. То, что сказано в стандарте C, достаточно — за исключением того, что оно оставляет ваш вопрос 1 без ответа.
  2. Q2 должен быть «Фазой 5», я думаю, с оговорками о том, что «поток токенов эквивалентен».
  3. Q3 — строго N / A, но Фаза 7, вероятно, является ответом.
  4. Q4 — «да», и он так говорит, потому что упоминает «escape-последовательности», а UCN — это escape-последовательности.
  5. Q5 тоже «Фаза 5».

Могут ли процессы, предусмотренные C ++ 11 на этапах 1 и 5, быть признаны соответствующими требованиям в формулировке C11 (за исключением необработанных строк)?

Я думаю, что они фактически одинаковы; Разница возникает в основном из-за проблем с литералом, характерных для C ++. Как правило, стандарты C и C ++ стараются не делать вещи совершенно разными, и, в частности, стараются, чтобы работа препроцессора и низкоуровневый символ разбирались одинаково в обоих (что стало проще, так как C99 добавил поддержку C ++ // комментарии, но которые, очевидно, стали сложнее с добавлением необработанных литералов в C ++ 11).

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

2

Другие решения

Во-первых, обратите внимание, что эти различия существуют с 1998 года; UCN были впервые представлены в C ++ 98, новом стандарте (ISO / IEC 14882, 1-е издание: 1998), а затем вошли в пересмотр C99 стандарта C; но комитет C (и существующие исполнители, и их ранее существовавшие реализации) не чувствовали, что путь C ++ был единственным способом добиться цели, особенно в угловых случаях и использовании меньших наборов символов, чем Unicode, или просто других; например, требование отправить таблицы сопоставления из независимо от поддерживаемых кодировок- Unicode был предметом озабоченности для поставщиков C в 1998 году.

  1. Стандарт C (сознательно) избегает принятия этого решения и позволяет компилятору выбирать, как поступить. Хотя ваши рассуждения, очевидно, имеют место в контексте наборов символов UTF-8, используемых как для источника, так и для исполнения, существует большой (и уже существующий) диапазон различных компиляторов C99 / C11, которые используют разные наборы; и комитет счел, что не должен слишком ограничивать исполнителей в этом вопросе. По моему опыту, большинство компиляторов поддерживают это на практике (по соображениям производительности).
  2. Из-за этой свободы некоторые компиляторы могут иметь ее идентичную после фазы 1 (как это должен делать компилятор C ++), в то время как другие могут оставить ее отличной вплоть до фазы 7 для символа первой степени; символы второй степени (в строке) должны быть одинаковыми после фазы 5, предполагая, что символ степени является частью расширенного набора символов выполнения, поддерживаемого реализацией.

Что касается других ответов, я не буду ничего добавлять к Джонатану.

Что касается вашего дополнительного вопроса о более детерминированном процессе C ++, который должен быть совместим со стандартом C, то, очевидно, цель — быть таковым; и если вы обнаружите угловой случай, который показывает иное (препроцессор, совместимый с C ++ 11, который не соответствует стандартам C99 и C11), то вам следует рассмотреть вопрос о том, чтобы спросить комитет WG14 о возможном дефекте.

Очевидно, что обратное неверно: можно написать препроцессор с обработкой UCN, который соответствует C99 / C11, но не стандартам C ++; самая очевидная разница с

#define str(t) #t
#define str_is(x, y)  const char * x = y " is " str(y)
str_is(hell°,      "hell°");
str_is(hell\u00B0, "hell\u00B0");

который C-совместимый препроцессор может отображать так же, как ваши примеры (и большинство так), и, как таковой, будет иметь отличные отображения; но у меня сложилось впечатление, что C ++ — совместимый препроцессор требуется для преобразования в (строго эквивалентный)

const char* hell°      = "hell°"       " is " "\"hell\\u00b0\"";
const char* hell\u00b0 = "hell\\u00b0" " is " "\"hell\\u00b0\"";

И последнее, но не менее важное: я считаю, что не так много компиляторов полностью соответствуют этому уровню детализации!

1