4 回答
Unicode 字符\u2780
超出char
数据类型的范围。你应该已经收到了这个编译器警告来告诉你:(至少我的 g++ 4.7.3 给出了它)
test.cpp:6:13: warning: multi-character character constant [-Wmultichar]
如果您想将 U+2780 之类的字符作为单个单元使用,则必须使用 widechar 数据类型wchar_t
,或者如果您有幸能够使用 C++11char32_t
或char16_t
. 请注意,一个 16 位单元不足以表示所有 Unicode 字符。
如果这对您不起作用,可能是因为默认的“C”语言环境不支持非 ASCII 输出。要解决该问题,您可以setlocale
在程序开始时调用;这样您就可以输出用户语言环境支持的全部字符:(可能支持也可能不支持您使用的所有字符)
#include <clocale>
#include <iostream>
using namespace std;
int main() {
setlocale(LC_ALL, "");
wcout << L'\u2780';
return 0;
}
当你写
cout << "\u2780";
编译器将 \u2780 转换为执行字符集中该字符的适当编码。那可能是 UTF-8,因此字符串最终有四个字节(三个用于字符,一个用于空终止符)。
如果您想在运行时生成字符,那么您需要一些方法在运行时执行与编译器在编译时执行的相同的 UTF-8 转换。
C++11 提供了一个方便的wstring_convert
模板和 codecvt facets 可以做到这一点,但是 gcc 附带的标准库实现 libstdc++ 尚未开始实现它们(从 gcc 4.8 开始)。下面展示了如何使用这些功能,但您需要使用不同的标准库实现或等待 libstdc++ 实现它们。
#include <codecvt>
int main() {
char32_t base = U'\u2780';
std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> convert;
std::cout << convert.to_bytes(base + 5) << '\n';
}
您还可以使用任何其他可用的方法来生成 UTF-8。例如,iconv、ICU 和手动使用 C++11 之前的 codecvt_byname 方面都可以工作。(我没有展示这些示例,因为该代码将比 . 所允许的简单代码涉及更多wstring_convert
。)
一种适用于少量字符的替代方法是使用文字创建一个字符串数组。
char const *special_character[] = { "\u2780", "\u2781", "\u2782",
"\u2783", "\u2784", "\u2785", "\u2786", "\u2787", "\u2788", "\u2789" };
std::cout << special_character[i] << '\n';
由于 C++11 §2.14.3/1,该程序打印一个整数:
多字符文字或包含无法在执行字符集中表示的单个 c-char 的普通字符文字是有条件的,具有 int 类型,并具有实现定义的值。
执行字符集就是char
可以表示的,即ASCII。
你得到的是 14851712,或者十六进制的 e29e80,它是 U+2780 的 UTF-8 表示。将 UTF-8(一种多字节编码)放入 anint
中既疯狂又愚蠢,但这就是您从“有条件支持的、实现定义的”功能中得到的。
要获取 UTF-32 值,请使用U'\u2780'
. 第一个U
指定char32_t
类型和 UTF-32 编码(即最多 31 位但没有代理对)。第二个\u
指定包含代码点的通用字符名称。要获得一个据称与 , 兼容的值wcout
,请使用L'\u2780'
,但这不一定使用 Unicode 运行时值,也不一定会获得超过两个字节的存储空间。
至于可靠地操作和打印 Unicode 代码点,正如其他答案所指出的那样,C++ 标准还没有完全实现。Joni 的回答是最好的方法,但它仍然假设编译器和用户的环境使用相同的语言环境,这通常不是真的。
您还可以使用在源代码中指定 UTF-8 字符串,u8"\u2780"
并使用类似std::locale::global( std::locale( "en_US.UTF-8" ) );
. 但这仍然有粗糙的边缘。Joni 建议使用 C 接口std::setlocale
而<clocale>
不是 C++ 接口std::locale::global
,<locale>
这是在 OS X 和其他平台上的 GCC 中破坏 C++ 接口的一种解决方法。这些问题对平台足够敏感,以至于您的 Linux 发行版很可能已将补丁放入他们自己的 GCC 包中。
在 Linux 中,我以最天真的方式成功地直接打印出任何 unicode:
std::cout << "ΐ , Α, Β, Γ, Δ, ,Θ , Λ, Ξ, ... ±, ... etc"