Является ли '\ u0B95' многостраничным литералом?

В предыдущем ответе, который я дал, я ответил на следующее предупреждение, вызванное тем фактом, что '\u0B95' требуется три байта, а также многохарактерный литерал:

warning: multi-character character constant [-Wmultichar]

Но на самом деле, я не думаю, что я прав, и я не думаю, что gcc тоже. Стандартные состояния:

Литерал обычного характера, содержащий более одного c- char, является многоканальным литералом.

Одно производственное правило для c- char является универсальным символьным именем (т.е. \uXXXX или \UXXXXXXXX). Поскольку \u0B95 является единственным c- char, это не многохарактерный литерал. Но теперь это становится беспорядочным. В стандарте также говорится:

Литерал обычного символа, который содержит один c- char, имеет тип char со значением, равным числовому значению кодирования c- char в наборе символов выполнения.

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

Объекты, объявленные как символы (char), должны быть достаточно большими, чтобы хранить любой элемент базового набора символов реализаций.

Поэтому, поскольку набор символов выполнения является надмножеством всех значений, которые может выполняться a char, мой символ может не соответствовать char.

Итак, какое значение имеет мой char? Кажется, это нигде не определено. Стандарт говорит, что для char16_t литералов, если значение не является представимым, программа плохо сформирована. Тем не менее, он ничего не говорит о обычных литералах.

Итак, что происходит? Это просто беспорядок в стандарте или мне что-то не хватает?

Ответ 1

Я бы сказал следующее:

Значение символьного литерала определяется реализацией, если оно выходит за пределы диапазона, определяемого реализацией для char (для литералов без предварительной настройки)... (Из раздела 2.14.3.4)

Если '\u0B95' выходит за пределы диапазона определения, определенного для char (что было бы, если char равно 8 бит), тогда это значение определяется реализацией, после чего GCC может сделать свое значение последовательностью из нескольких c-char s, становясь таким образом многосимвольным литералом.

Ответ 2

Кто-нибудь отправил ответ, который правильно ответил на вторую часть моего вопроса (какое значение будет иметь значение char?), но с тех пор удалил свой пост. Поскольку эта часть была правильной, я воспроизведу ее здесь вместе с моим ответом для первой части (это многоканальный литерал?).


'\u0B95' не является многосимвольным литералом, и gcc здесь ошибается. Как указано в вопросе, многохарактерный литерал определяется (§2.14.3/1):

Литерал обычного характера, содержащий более одного c- char, является многоканальным литералом.

Поскольку универсальное имя-символа является одним расширением c- char, буква '\u0B95' содержит только один c- char. Было бы разумно, если бы обычные литералы не могли содержать имя универсального символа для \u0B95 для обозначения шести отдельных символов (\, u, 0 и т.д.), Но я не могу найти это ограничение нигде, Следовательно, это единственный символ, а литерал - не многохарактерный литерал.

Чтобы поддержать это, почему его можно считать несколькими символами? На данный момент мы даже не дали ему кодировку, поэтому мы не знаем, сколько байтов потребуется. В UTF-16 это займет 2 байта, в UTF-8 это займет 3 байта, а в некоторой воображаемой кодировке может принимать только 1 байт.

Итак, какое значение будет иметь символьный литерал? Сначала имя универсального символа сопоставляется с соответствующей кодировкой в ​​наборе символов выполнения, если только оно не имеет сопоставления, и в этом случае оно имеет кодирование, определяемое реализацией (§2.14.3/5):

Универсальное имя-символ переводится в кодировку в соответствующем символьном наборе символов символа. Если такой кодировки нет, имя универсального символа преобразуется в кодировку, определяемую реализацией.

В любом случае литерал char получает значение, равное числовому значению кодировки (§2.14.3/1):

Литерал обычного символа, который содержит один c- char, имеет тип char со значением, равным числовому значению кодирования c- char в наборе символов выполнения.

Теперь важная часть, неудобно спрятанная в другом абзаце далее в разделе. Если значение не может быть представлено в char, оно получает значение, определенное реализацией (§2.14.3/4):

Значение символьного литерала определяется реализацией, если оно выходит за пределы определенного для реализации диапазона, определенного для char (для литералов без префикса)...

Ответ 3

Вы правы, в соответствии с spec '\u0B95' является char -типом символа символа со значением, равным символьной кодировке в наборе символов выполнения. И вы правы, что спецификация ничего не говорит о том, что это невозможно для литералов char из-за того, что один char не может представить это значение. Поведение undefined.

В комитете по этому вопросу представлены отчеты о дефектах: например, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#912

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

Это то, что реализовано в clang: http://coliru.stacked-crooked.com/a/952ce7775dcf7472

Ответ 4

Поскольку у вас нет префикса кодировки символов gcc (и любого другого совместимого компилятора), вы увидите '\u0B95' и подумайте 1) char type и 2) multicharacter, потому что в строке содержится более одного кода char.

  • u'\u0B95' является символом UTF16.
  • u'\u0B95\u0B97' - многосимвольный символ UTF16.
  • U'\ufacebeef' является символом UTF32.

и др.