int main() {
std::cout << "\u2654" << std::endl; // Result #1: ♔
std::cout << U'\u2654' << std::endl; // Result #2: 9812
std::cout << U'♔' << std::endl; // Result #3: 9812
return 0;
}
我无法理解Unicode如何使用C ++。为什么文字不输出终端中的文字?
我有点想要这样的事情发挥作用;
char32_t txt_representation() { return /* Unicode codepoint */; }
注意:源是UTF-8,终端,坐在macOS Sierra,CLion。
答案 0 :(得分:7)
C ++在其类型系统中并没有真正的“字符”概念。 char
,wchar_t
,char16_t
和char32_t
都被认为是整数的种类。因此,'x'
,L'x'
,U'x'
等字符文字都是数字。 operator<<
专门针对char
,这就是
cout << "endl is almost never necessary" << '\n';
和
做同样的事情cout << "endl is almost never necessary\n";
但是*char_t
没有类似物,所以你的宽字符文字被静默转换为int
并打印出来。我个人从不使用iostream,因此我实际上并不知道如何说服operator<<
打印一个数字作为其Unicode代码点,但可能有一些方法可以做到。
类型系统中“字符串”和“整数数组”之间存在更强的区别,因此在提供字符串文字时,您可以获得预期的输出。但请注意,cout << L"♔"
不会提供您期望的输出,并且cout << "♔"
甚至不能保证编译。 cout << u8"♔"
将在符合C ++ 11标准的系统上工作,其中窄字符编码实际上是UTF-8,但如果字符编码是其他内容,则可能会产生mojibake。
(是的,这有点复杂,没有任何借口可以存在。这部分是因为从C继承的向后兼容性约束,部分是因为它在1990年代之前设计,在Unicode接管之前这个世界,部分是因为C ++字符串和流类中的许多设计错误都没有明显的错误,直到修复它们为时已晚。)
答案 1 :(得分:2)
不支持将宽字符打印到窄流,并且根本不起作用。 (它“有效”但结果不是你想要的。)
不支持将多字节窄字符串打印到宽流,并且根本不起作用。 (它“有效”但结果不是你想要的。)
在支持Unicode的系统上,std::cout << "\u2654"
按预期工作。 std::cout << u8"\u2654"
也是如此。最适当设置基于Unix的操作系统是准备好Unicode的。
在支持Unicode的系统上,如果正确设置程序区域设置,std::wcout << L'\u2654'
应该按预期工作。这是通过以下呼叫完成的:
::setlocale(LC_ALL, "");
或者
::std::locale::global(::std::locale(""));
注意“应该”;对于某些编译器/库,此方法可能根本不起作用。这些编译器/库是一个缺陷。我在看你,libc ++。它可能是也可能不是正式的错误,但我将其视为一个错误。
您应该在所有希望使用Unicode的程序中设置您的语言环境,即使这似乎没有必要。
在同一程序中混用cout
和wcout
不起作用且不受支持。
std::wcout << U'\u2654'
不有效,因为这会将wchar_t
流与char32_t
字符混合在一起。 wchar_t
和char32_t
是不同的类型。我想正确设置std::basic_stream<char32_t>
可以使用char32_t
字符串,标准库不会提供任何字符串。
char32_t
的字符串适用于存储和处理Unicode代码点。不要将它们直接用于格式化输入和输出。 std::wstring_convert可用于来回转换它们。
TL; DR适用于std::stream
和std::string
s,或者(如果您不在libc ++上)std::wstream
和std::wstring
s。
答案 2 :(得分:2)
Unicode和C ++
有几种unicode编码:
char
)char16_t
)的序列。 char32_t
)。 以下是James McNellis的 excellent video tutorial on unicode with C++ 。他解释了你需要知道的关于字符集编码,unicode及其不同编码以及如何在C ++中使用它的所有内容。
您的代码
"\u2654"
是一个狭窄的字符串文字,其类型数组为char
。 white chess king unicode character将被编码为与UTF-8编码({ 0xe2, 0x99, 0x94 }
)对应的3个连续字符。因为我们在一个字符串中,没有问题,其中有几个字符。由于您的控制台区域设置当然使用UTF8,因此它将在显示字符串时正确解释序列。
U'\u2654'
是char32_t
类型的字符文字(因为大写的U)。因为它是char32_t(而不是char),所以它不会显示为char,而是显示为整数值。十进制的值是9812.如果你使用十六进制,你会立即认出它。
最后U'♔'
遵循相同的逻辑。但请注意,您在源代码中嵌入了一个unicode字符。只要编辑器的字符编码与编译器期望的源代码编码匹配,这就没问题。但是,如果文件被复制(没有转换)到期望不同编码的环境,这可能会导致不匹配。
答案 3 :(得分:1)
在我的系统上,我无法使用std::cout
与std::wcout
混合,并获得明智的结果。所以你必须分开做这些。
您应该使用std::locale::global(std::locale(""));
将区域设置设置为本机系统的区域设置。
另外使用宽流作为后两个输出
或者:
std::locale::global(std::locale(""));
std::cout << "\u2654" << std::endl;
或者:
std::locale::global(std::locale(""));
std::wcout << L"\u2654" << std::endl;
std::wcout << L'♔' << std::endl;
这应该鼓励输出流在本地系统的编码和utf8
(第一个例子)或ucs16/utf32
(第二个例子)之间进行转换。
我认为最安全的第一个例子(编辑可以有其他编码)最好在字符串前面添加u8
:
std::cout << u8"\u2654" << std::endl;