C11和C ++ 11都支持源文件中的扩展字符,以及通用字符名称(UCN),它们允许用户只输入字符而不是基本源字符集中的字符。
C ++ 11还定义了编译的几个翻译阶段。特别是,扩展字符在翻译的第一阶段被归一化为UCN,如下所述:
§C++ 11 2.2p1.1:
物理源文件字符映射在一个 实现定义的方式,基本源字符集 (引入行尾指标的换行符)if 必要。接受的物理源文件字符集是 实现定义。 Trigraph序列(2.4)被替换为 相应的单字符内部表示。任何来源 不替换基本源字符集(2.3)中的文件字符 通过指定该角色的通用字符名称。 (一个 实现可以使用任何内部编码,只要是实际的 源文件中遇到的扩展字符,并且相同 扩展字符在源文件中表示为 通用字符名称(即使用\ uXXXX表示法)是 处理等效,除非这个替换在a。中被还原 原始字符串文字。)
因此,我的问题是:
是否符合标准的程序编译
#include <stdio.h> int main(void){ printf("\é\n"); printf("\\u00e9\n"); return 0; }
失败,编译和打印
é é
或编译和打印
\u00e9 \u00e9
,什么时候跑?
我的观点是答案是它成功编译并打印\u00e9
,因为根据上面的§2.2p1.1,我们有
实现可以使用任何内部编码,只要在源文件中遇到实际的扩展字符,并且在源文件中表示的相同扩展字符作为通用-character-name (即使用\ uXXXX表示法)处理等效,除非在原始字符串文字中还原此替换。,我们不是原始字符串文字。
然后是
printf("\é\n");
映射到printf("\\u00e9\n");
。"\\u00e9\n"
是一个\\
映射到\
,并且片段u00e9
不会被识别为UCN,因此按原样打印。不幸的是,现存的编译器不同意我的看法。我已经用GCC 4.8.2和Clang 3.5进行了测试,这是他们给我的:
GCC 4.8.2
$ g++ -std=c++11 -Wall -Wextra ucn.cpp -o ucn
ucn.cpp: In function 'int main()':
ucn.cpp:4:9: warning: unknown escape sequence: '\303' [enabled by default]
printf("\é\n");
^
$ ./ucn
é
\u00e9
Clang 3.5
$ clang++ -std=c++11 -Wall -Wextra ucn.cpp -o ucn
ucn.cpp:4:10: warning: unknown escape sequence '\xFFFFFFC3' [-Wunknown-escape-sequence]
printf("\é\n");
^
ucn.cpp:4:12: warning: illegal character encoding in string literal [-Winvalid-source-encoding]
printf("\é\n");
^
2 warnings generated.
$ ./ucn
é
\u00e9
我使用é
检查C3 A9
字符是否为hexdump -C ucn.cpp
,与预期的UTF-8编码一致。我还验证了普通printf("é\n");
或printf("\u00e9\n");
完美无缺,所以这不是被测试的编译器无法读取UTF-8源文件的问题。
谁是对的?