В предыдущий ответ я дал, Я ответил на следующее предупреждение, вызванное тем, что '\u0B95'
требует три байта и поэтому многозначный буквальный:
warning: multi-character character constant [-Wmultichar]
Но на самом деле, я не думаю, что я прав, и я не думаю, что gcc тоже. Стандарт гласит:
Обычный символьный литерал, содержащий более одного с-символ это многозначный буквальный.
Одно производственное правило для с-символ это универсальный характер имя (Т.е. \uXXXX
или же \UXXXXXXXX
). поскольку \u0B95
это один с-символ, это не многозначный литерал. Но теперь это становится грязным. Стандарт также гласит:
Обычный символьный литерал, который содержит один с-символ имеет тип
char
со значением, равным числовому значению кодирования с-символ в наборе символов выполнения.
Так что мой литерал имеет тип char
и значение символа в наборе символов выполнения (или значение, определенное реализацией, если оно не существует в этом наборе). char
определяется как достаточно большой для хранения любого члена базового набора символов (который на самом деле не определен стандартом, но я предполагаю, что это означает базовый набор символов выполнения):
Объекты, объявленные как символы (char), должны быть достаточно большими для хранения любого члена базового набора символов реализации.
Следовательно, поскольку набор символов выполнения является надмножеством всех значений char
может держать, мой персонаж может не вписаться в char
,
Так какая ценность делает мой char
иметь? Кажется, это нигде не определено. Стандарт говорит, что для char16_t
литералы, если значение не представимо, программа некорректна. Хотя ничего не говорится об обычных литералах.
Так, что происходит? Это просто беспорядок в стандарте или я что-то упустил?
Я бы сказал следующее:
Значение символьного литерала определяется реализацией, если он выходит за пределы определенного реализацией диапазона, определенного для
char
(для литералов без префикса) … (Из раздела 2.14.3.4)
Если '\u0B95'
выходит за пределы определенного реализацией диапазона, определенного для char
(что было бы, если char
равен 8 битам), его значение определяется реализацией, после чего GCC может сделать свое значение последовательностью из нескольких c-char
с, таким образом, становясь многозначным буквальным.
Кто-то опубликовал ответ, который правильно ответил на вторую часть моего вопроса (какое значение char
есть?) но с тех пор удалил свой пост. Поскольку эта часть была правильной, я воспроизведу ее здесь вместе со своим ответом для первой части (это литерал с несколькими символами?).
'\u0B95'
не является литералом, состоящим из нескольких символов, и здесь gcc ошибается. Как указано в вопросе, литерал с несколькими символами определяется как (§2.14.3 / 1):
Обычный символьный литерал, содержащий более одного с-символ это многозначный буквальный.
Так как универсальный характер имя это одно расширение с-символ, буквальный '\u0B95'
содержит только один с-символ. Было бы разумно, если бы обычные литералы не могли содержать универсальный характер имя за \u0B95
считаться шестью отдельными символами (\
, u
, 0
и т. д.), но я не могу найти это ограничение нигде. Следовательно, это один символ, а литерал не является литералом с несколькими символами.
Для дальнейшей поддержки этого, почему было бы это будет считаться несколько символов? На данный момент мы даже не дали ему кодировку, поэтому мы не знаем, сколько байт это займет. В UTF-16 это займет 2 байта, в UTF-8 это займет 3 байта, а в некотором воображаемом кодировании это может занять всего 1 байт.
Так какое значение будет иметь символьный литерал? Сначала универсальный характер имя сопоставляется с соответствующей кодировкой в наборе символов выполнения, если только он не сопоставлен, в этом случае он имеет кодирование, определяемое реализацией (§2.14.3 / 5):
Универсальное имя символа преобразуется в кодировку, в соответствующем наборе символов выполнения, указанного символа. Если такой кодировки нет, универсальное символьное имя преобразуется в кодировку, определяемую реализацией.
В любом случае, char
литерал получает значение, равное числовому значению кодировки (§2.14.3 / 1):
Обычный символьный литерал, который содержит один с-символ имеет тип
char
со значением, равным числовому значению кодировки c-char в наборе символов выполнения.
Теперь важная часть, неудобно спрятанная в другом абзаце далее в разделе. Если значение не может быть представлено в char
, это получает определенное реализацией значение (§2.14.3 / 4):
Значение символьного литерала определяется реализацией, если оно выходит за пределы определенного реализацией диапазона, определенного для
char
(для литералов без префикса) …
Вы правы, согласно спецификации '\u0B95'
является символьным литералом с типом символа со значением, равным кодировке символа в наборе символов выполнения. И вы правы, что в спецификации ничего не сказано о случае, когда это невозможно для букв литералов из-за того, что один символ не может представлять это значение. Поведение не определено.
По данному вопросу в комитет поступили сообщения о дефектах: например, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#912
Похоже, что в настоящее время предлагается указать, что эти символьные литералы также int
s и имеют определенные значения реализации (хотя предложенный язык не совсем подходит для этого), как и многоканальные литералы. Я не фанат этого решения, и я думаю, что лучшее решение — сказать, что такие литералы плохо сформированы.
Вот что реализовано в Clang: http://coliru.stacked-crooked.com/a/952ce7775dcf7472
Поскольку у вас нет префикса кодировки символов, gcc (и любой другой совместимый компилятор) увидит '\u0B95'
и подумайте: 1) тип символа и 2) мультисимвол, потому что в строке более одного кода символа.
u'\u0B95'
является символом UTF16.u'\u0B95\u0B97'
является мультисимвольным символом UTF16.U'\ufacebeef'
является символом UTF32и т.п.