Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/160.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ u8文本应该如何工作?_C++_C++11 - Fatal编程技术网

C++ u8文本应该如何工作?

C++ u8文本应该如何工作?,c++,c++11,C++,C++11,难以理解u8文本的语义,或者更确切地说,难以理解g++4.8.1上的结果 const std::string utf8 = u8"åäö"; // or some other extended ASCII characters assert( utf8.size() == 3); 这是我的期望: const std::string utf8 = u8"åäö"; // or some other extended ASCII characters assert( utf8.size() >

难以理解u8文本的语义,或者更确切地说,难以理解g++4.8.1上的结果

const std::string utf8 = u8"åäö"; // or some other extended ASCII characters
assert( utf8.size() == 3);
这是我的期望:

const std::string utf8 = u8"åäö"; // or some other extended ASCII characters
assert( utf8.size() > 3);
这是g++4.8.1上的结果

const std::string utf8 = u8"åäö"; // or some other extended ASCII characters
assert( utf8.size() == 3);
  • 源文件是ISO-8859(-1)
  • 我们使用以下编译器指令:-m64-std=c++11-pthread-O3-fpic
在我的世界里,不管源文件的编码是什么,生成的utf8字符串都应该大于3

或者,我是否完全误解了u8的语义以及它所针对的用例?请开导我

更新

如果我像许多人建议的那样明确地告诉编译器源文件的编码方式,我就得到了u8文本的预期行为,常规文本也会被编码为utf8

即:

const std::string utf8 = u8"åäö"; // or some other extended ASCII characters
assert( utf8.size() > 3);
assert( utf8 == "åäö");
  • 编译器指令:g++-m64-std=c++11-pthread-O3-finput charset=ISO8859-1
  • 尝试了从iconv定义的其他一些字符集,例如:ISO_8859-1等等

我现在比以前更困惑了…

前缀
u8
实际上只是指“编译此代码时,从该文本生成UTF-8字符串”。它没有说明编译器应该如何解释源文件中的文本

因此,有几个因素在起作用:

  • 源文件是用哪种编码编写的(在您的例子中,显然是ISO-8859)。根据这种编码,字符串文字是“åäö”(3个字节,包含值0xc5、0xe4、0xf6)
  • 编译器在读取源文件时采用哪种编码?(我怀疑GCC默认为UTF-8,但我可能错了
  • 编译器对目标文件中生成的字符串使用的编码。您可以通过
    u8
    前缀将其指定为UTF-8
  • 最有可能的情况是,#2是错误的地方。如果编译器将源文件解释为ISO-8859,那么它将读取三个字符,将它们转换为UTF-8,然后写入这些字符,结果为您提供一个6字节(我认为这些字符中的每一个都编码为UTF-8中的2字节)字符串

    但是,如果它假定源文件是UTF-8,那么它根本不需要进行转换:它读取3个字节,它假定这些字节是UTF-8(即使它们是UTF-8的无效垃圾值),并且由于您要求输出字符串也是UTF-8,所以它只输出相同的3个字节

    您可以告诉GCC使用
    -finput charset
    采用哪种源代码编码,或者您可以将源代码编码为UTF-8,或者您可以使用字符串文本中的
    \uxxx
    转义序列(
    \u00E5
    而不是
    å

    编辑: 为了澄清一点,当您在源代码中指定带有
    u8
    前缀的字符串文字时,您告诉编译器“无论您在读取源文本时使用哪种编码,请在将其写入目标文件时将其转换为UTF-8”。您没有说明源文本应该如何解释。这取决于编译器的决定(可能基于您传递给它的标志,可能基于进程的环境,或者可能只是使用硬编码的默认值)

    如果源文本中的字符串包含字节0xc5、0xe4、0xf6,并且您告诉它“源文本编码为ISO-8859”,那么编译器将识别“字符串由字符组成”“。它将看到
    u8
    前缀,并将这些字符转换为UTF-8,将字节序列0xc3、0xa5、0xc3、0xa4、0xc3、0xb6写入目标文件。在这种情况下,您将得到一个有效的UTF-8编码文本字符串,其中包含字符“åäö”的UTF-8表示形式

    但是,如果源文本中的字符串包含相同的字节,并且您让编译器相信源文本编码为UTF-8,那么编译器可以做两件事(取决于实现:

    • 它可能尝试将字节解析为UTF-8,在这种情况下,它将识别“这不是有效的UTF-8序列”,并发出错误。这就是Clang所做的
    • 或者,它可能会说“好的,我这里有3个字节,我被告知它们构成一个有效的UTF-8字符串。我会抓住它们,看看会发生什么”。然后,当它应该将字符串写入对象文件时,它会“好的,我有以前的3个字节,它们被标记为UTF-8。这里的
      u8
      前缀意味着我应该把这个字符串写为UTF-8。酷,那就不需要做转换了。我只写这3个字节,我就完成了。”这就是GCC所做的
    <> >两个都是有效的。C++语言没有声明编译器需要检查传递给它的字符串字的有效性。 但在这两种情况下,请注意,
    u8
    前缀与您的问题无关。这只是告诉编译器从“读取字符串时使用的任何编码”转换为UTF-8“。但即使在进行此转换之前,字符串已被乱码,因为字节对应于ISO-8859字符数据,但编译器认为它们是UTF-8(因为您没有告诉它)

    您看到的问题只是编译器在从源文件读取字符串文字时不知道使用哪种编码


    您注意到的另一件事是,没有前缀的“传统”字符串文字将使用编译器喜欢的任何编码进行编码。
    u8
    前缀(以及相应的UTF-16和UTF-32前缀)精确地让你精确地指定你希望编译器编写输出的编码。普通的前缀较少文字根本不指定一个编码,留给编译器来决定一个。

    为了说明这个讨论,这里有一些例子。让我们考虑代码:

    int main() {
      std::cout << "åäö\n";
    }
    
    换句话说,每个“grapheme集群”有两个字节(根据unicode术语,即
    % ./a.out | od -txC
    0000000 e5 e4 f6 0a
    
    % objdump -s -j .rodata a.out
    
    a.out:     file format elf64-x86-64
    
    Contents of section .rodata:
    400870 01000200 00e5e4f6 0a00               ..........
    
    % ./a.out | od -txC
    0000000 c3 a5 c3 a4 c3 b6 0a
    
    % ./a.out | od -txC
    0000000 e5 e4 f6 0a
    
    int main() {
      std::cout << u8"åäö\n";
    }
    
    % ./a.out | od -txC
    0000000 c3 a5 c3 a4 c3 b6 0a
    
    % ./a.out | od -txC
    0000000 c3 a5 c3 a4 c3 b6 0a