C11& C ++ 11 Exended和Universal Character Escaping

时间:2015-05-10 16:38:39

标签: c++ c c++11 language-lawyer c11

上下文

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表示法)处理等效,除非在原始字符串文字中还原此替换。,我们不是原始字符串文字。

然后是

  • 在阶段1中,printf("\é\n");映射到printf("\\u00e9\n");
  • 在阶段3中,源文件被分解为预处理令牌(§2.2p1.3),其中 string-literal "\\u00e9\n"是一个
  • 在阶段5中,转换字符文字或字符串文字中的每个源字符集成员,以及字符文字或非原始字符串文字中的每个转义序列和通用字符名称到执行字符集的相应成员(§2.2p1.5)。因此,通过最大蒙克原则,\\映射到\,并且片段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源文件的问题。

谁是对的?

0 个答案:

没有答案