'\u0B95'是一个多字符字面量吗?

10

我之前的回答中,我回应了以下警告的原因,即'\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)的对象应足够大,以存储实现基本字符集中的任何成员。

因此,由于执行字符集是所有 char 可以容纳的值的超集,我的字符可能无法适合 char 中。

那么我的 char 具有什么值?这似乎没有定义在任何地方。标准确实说,对于 char16_t 字面量,如果该值不可表示,则程序是非法的。但它未提及普通字面量。

那么发生了什么?这只是标准中的混乱还是我错过了什么?


由于执行字符集中不存在这样的映射,因此我会将其解读为未定义行为,并且具有数值等于c-char编码的值的值。 - Lightness Races in Orbit
映射可能存在,取决于实现定义的执行字符集。 - Joseph Mansfield
通用字符名称将被翻译成所命名字符的适当执行字符集编码。如果没有这样的编码,则通用字符名称将被翻译成实现定义的编码。(2.14.3.5) - fefe
那是一个独立的问题。假设该字符可以被编码在执行字符集中,那么char字面值的值是什么?或者它是一个多字符字面值吗?如果不能,如果实现定义的值无法存储在char中,会怎样呢? - Joseph Mansfield
4个回答

1
我会这样论述:

如果字符字面量超出了为 char 定义的实现定义范围(对于没有前缀的字面量),则其值是实现定义的……(来自第2.14.3.4节)

如果 '\u0B95' 超出了为 char 定义的实现定义范围(如果 char 是8位,则是这种情况),那么它的值就是实现定义的,此时GCC可以将其值变成多个 c-char 的序列,从而成为一个多字符字面量。


1
该段落是关于数字转义序列而不是通用字符名称的。你需要下一段! - Luc Danton
@LucDanton,我觉得这句话不仅适用于数字转义序列。我认为它只是被放在一个愚蠢的段落中。 - Joseph Mansfield
我也不相信这适用于UCN。除了上下文之外,相关委员会缺陷报告的讨论并未表明这可能适用于UCN。 - bames53

1

有人发布了一个正确回答了我问题的第二部分(char将具有什么值?),但是后来删除了他们的帖子。既然那一部分是正确的,我将在此重现它,并附上我对第一部分的答案(是否为多字符文字?)。


'\u0B95' 不是多字符字面值,gcc 在这里犯了错误。如问题所述,多字符字面值由(§2.14.3/1)定义:

包含多个 c-char 的普通字符字面值是一个 多字符字面值

由于 universal-character-namec-char 的一种扩展形式,因此字面值 '\u0B95' 仅包含一个 c-char。如果普通字面值不能包含 universal-character-name,那么对于 \u0B95 被视为六个单独的字符(\u0 等)是有道理的,但我找不到这种限制。因此,它是一个单一的字符,该字面值不是多字符字面值。

为了进一步支持这一点,为什么会被认为是多个字符呢?此时我们甚至还没有给它编码,因此我们不知道它需要占用多少字节。在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(对于没有前缀的字面量)定义的实现定义范围,其值就是实现定义的。


1
我已经恢复了我的回答。我之前删除它是因为我不想留下一个不完整的答案,因为我只回答了问题的一部分。 - Cornstalks
@Cornstalks 好的,没问题。我在看到你的回答时很喜欢它,但是直到你删除它之后才有机会回复。 - Joseph Mansfield
1
“为什么它被认为是多个字符?”GCC故意以这种方式实现了UCNs,以匹配在源代码中使用字符文字的行为。据我所知,最初字面上写这些字符的行为并非有意为之。 - bames53

1
您是正确的,根据规范,'\u0B95' 是一个 char 类型的字符字面值,其值等于执行字符集中字符的编码。您也是对的,规范没有提到由于单个字符无法表示该值而对char字面值不可能情况下的处理方法。行为是未定义的。
关于这个问题,委员会已经提交了缺陷报告:例如 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#912
目前提出的解决方案似乎是指定这些字符字面值也是 int,并具有实现定义的值(虽然拟议的语言不完全正确),就像多字符字面值一样。我不喜欢这种解决方案,我认为更好的解决方案是说这种字面值是非法的。
这是 Clang 中实现的内容:http://coliru.stacked-crooked.com/a/952ce7775dcf7472

我认为gcc支持多字符字面量是因为在C语言中,人们使用它们代替枚举等。可能委员会也是这样想的 - 向后兼容。我考虑添加一个注释,如果前两个字符是'\'和'u'或'U',则需要考虑编码前缀。此外,gcc默认会发出警告。 - emsr
@emsr,是的,人们仍然使用多字符字面量,例如用于FourCC(http://en.wikipedia.org/wiki/FourCC)。 GCC和clang都对多字符字面量具有相同的“实现定义”行为。不同之处在于,GCC将字面量中的有效UTF-8序列视为C ++语法中的多个_c-char_,但clang正确地将其识别为单个_c-char_。 - bames53

0

由于您没有字符编码前缀gcc(以及任何其他符合标准的编译器)将看到'\u0B95'并认为1)char类型和2)multicharacter,因为字符串中有多个字符代码。

  • u'\u0B95'是一个UTF16字符。
  • u'\u0B95\u0B97'是一个多字符UTF16字符。
  • U'\ufacebeef'是一个UTF32字符。

等等。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接