Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/139.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++ 为什么unicode字符在std::string中存储为UTF-8,在wchar\u t中存储为UTF-16/32?_C++_Unicode_Utf 8 - Fatal编程技术网

C++ 为什么unicode字符在std::string中存储为UTF-8,在wchar\u t中存储为UTF-16/32?

C++ 为什么unicode字符在std::string中存储为UTF-8,在wchar\u t中存储为UTF-16/32?,c++,unicode,utf-8,C++,Unicode,Utf 8,我有一小段代码: #include <locale.h> #include <stdlib.h> #include <stdio.h> #include <string> wchar_t widec('€'); wchar_t widecl(L'€'); std::string tc("€"); int main(int argc, char *argv[]) { printf("printf as hex - std::string

我有一小段代码:

#include <locale.h>
#include <stdlib.h>
#include <stdio.h>
#include <string>

wchar_t widec('€');
wchar_t widecl(L'€');
std::string tc("€");

int main(int argc, char *argv[])
{
    printf("printf as hex - std::string tc(\"€\") = %x %x %x\n\r", tc.c_str()[0], tc.c_str()[1], tc.c_str()[2]);
    printf("printf as hex - wchar_t widec('€') = %x\n\r", widec);
    printf("printf as hex - wchar_t widecl(L'€') = %x\n\r", widecl);

    return 0;
}
我不明白两件事

  • 为什么
    tc.c_str()
    (确切地说,它的
    [0]
    [1]
    [2]
    索引)打印为UTF-8,看起来像UTF-16/32,前导FF字节

  • 为什么初始化相同的
    wchar\u t
    变量会根据是否使用
    L
    前缀给出不同的输出,即使用它似乎会产生UTF-16/32内容,而UTF-8没有
    L
    前缀,这是为什么

  • 没有显式符号说明符的
    char
    是有符号的
    无符号的
    ,具体取决于编译器。该标准没有规定默认类型,它是编译器供应商的选择

    char
    传递到
    print()
    会将调用堆栈上的值从8位扩展到32位。然后
    %x
    打印该32位值的位,默认情况下忽略前导零(除非在
    %x
    上使用长度说明符来保留它们)。8位值如何扩展到32位取决于其实际类型

    在您的例子中,您看到的额外的
    f
    s是由于
    char
    值是符号扩展的。
    0xEx
    0x8x
    0xAx
    的高位均为1,因此在扩展期间,1用于填充高位24位。这意味着您的编译器将
    char
    实现为
    signed
    类型,并将值扩展到
    signed int
    。您可以手动键入将
    char
    值强制转换为
    unsigned
    ,强制它们进行零扩展

    printf("printf as hex - std::string tc(\"€\") = %x %x %x\n",
           (unsigned char) tc[0], (unsigned char) tc[1], (unsigned char) tc[2]);
    
    (注意,我删除了
    c_str()
    的用法,在您的示例中不需要它)

  • 不带任何前缀的
    “€”和
    “€”
    的解释取决于源文件保存为的编码以及编译器配置为在其中操作的编码

    如果源代码文件保存在UTF-8中(要强制使用UTF-8文本,可以在C++11及更高版本中使用
    u8
    前缀),则无前缀的
    “€”和
    “€”文本可以在UTF-8中。以不同的编码保存文件,您将看到不同的结果。然后将该解释的结果按原样分配给
    tc
    ,并在
    widec
    中按原样编码为
    wchar\t

    另一方面,
    L
    前缀迫使编译器将
    L'€'
    解释为宽文本而不是窄文本,因此不存在如何解释它的问题。它知道文本是Unicode,因此在将其编码为
    wchar\u t
    值之前,它先确定Unicode码点值(
    wchar\u t
    在Windows上是16位,在其他平台上是32位),然后在
    widecl
    中进行编码。
    的Unicode码点为


  • “它知道文字是Unicode”标准中没有要求宽字符串使用Unicode字符集。
    L'€'
    的结果是实现定义的。如果需要UTF-16,则必须使用
    u'€'
    ,而对于UTF-32,则必须使用
    u'€'
    。字符太小,无法作为UTF-16或32的编码元素。他们没有确定wchar_t的大小,这让wchar_t陷入了困境,后来不得不添加char16_t和char32_t。
    printf("printf as hex - std::string tc(\"€\") = %x %x %x\n",
           (unsigned char) tc[0], (unsigned char) tc[1], (unsigned char) tc[2]);