还有 char8_t呢?
我假设某个地方有一些C ++ 20决策,但我找不到。还有P1428,但DOC不提任何东西printf()家庭VS char8_t *或char8_t。
使用std::cout建议可能是一个答案。不幸的是,它不再编译了。
// does not compile under C++20
// error : overload resolution selected deleted operator '<<'
// see P1423, proposal 7
std::cout << u8"A2";
std::cout << char8_t ('A');
Run Code Online (Sandbox Code Playgroud)
对于C 2.x和char8_t
请从这里开始。
更新资料
我用u8序列中的单个元素做了更多测试。这确实是行不通的。char8_t *要printf("%s")工作,但char8_t到printf("%c")是等待发生的事故。
请参阅-https ://wandbox.org/permlink/6NQtkKeZ9JUFw4Sd-根据当前现状,问题char8_t尚未实现char8_t *。-让我重复一遍:没有实现的类型可以保存char8_t *序列中的单个元素。
如果您想要单个u8字形,则需要将其编码为u8字符串
char8_t const * single_glyph = u8"?";
Run Code Online (Sandbox Code Playgroud)
而且目前看来,打印上述一种肯定的方法是
// works with warnings
std::printf("%s", single_glyph ) ;
Run Code Online (Sandbox Code Playgroud)
要开始阅读此主题,可能需要这两篇论文
以该顺序。
我的主要DEVENV是VisualStudio 2019,同时包含VS随附的MSVC和CLANG 8.0.1。使用std:c ++ latest。开发人员机器为WIN10 [版本10.0.18362.476]
\n\nchar8_t * 的 printf() 格式字符是什么?
\n
没有将打印char8_t*为字符串的格式说明符。从技术上讲,使用%s是一种未定义的行为,因为类型不匹配,clang 会警告您(https://godbolt.org/z/xcs9Wj):
printf("%s", u8"\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!");\nRun Code Online (Sandbox Code Playgroud)\n...: warning: format specifies type \'char *\' but the argument has type \'const char8_t *\' [-Wformat]\n printf("%s", u8"\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!");\n ~~ ^~~~~~~~~~~~~~~~\n %s\nRun Code Online (Sandbox Code Playgroud)\n所以你唯一能做的就是将这样的字符串打印为指针,但这%p并不是很有用。
iostream 也不支持char8_t字符串。例如,这不能在 C++20 中编译:
...: warning: format specifies type \'char *\' but the argument has type \'const char8_t *\' [-Wformat]\n printf("%s", u8"\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!");\n ~~ ^~~~~~~~~~~~~~~~\n %s\nRun Code Online (Sandbox Code Playgroud)\n在大多数平台上,普通char字符串已经是 UTF-8,在带有 MSVC 的 Windows 上,您可以使用 /utf-8 进行编译,这将为您在主要操作系统上提供 Unicode 支持。
对于可移植的 Unicode 输出,您可以使用 {fmt} 库,例如 ( https://godbolt.org/z/3ejsaG ):
\nstd::cout << u8"\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!";\nRun Code Online (Sandbox Code Playgroud)\n印刷:
\n\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!\nRun Code Online (Sandbox Code Playgroud)\n免责声明:我是 {fmt} 的作者。
\n我是C++的char8_t P0482和P1423提案以及 C 的N2231提案(尚未被接受)的作者。
让我们想想以下应该做什么:
printf("Hello %s\n", u8"Jöel");
std::cout << "Hello " << u8"Jöel" << "\n";
Run Code Online (Sandbox Code Playgroud)
实际上,让我们再退一步。标准输出的接收端需要什么编码?有几种可能性。如果标准输出连接到控制台/终端,则预期的编码是控制台/终端配置的编码。在美国的 Windows 系统上,这很可能是CP437。在 UNIX/Linux 系统上,这可能是 UTF-8。在美国的 z/OS 系统上,这可能是EBCDIC 代码页 037。如果标准输出已被重定向,则预期的编码可能取决于区域设置。在美国的 Windows 系统上,这意味着活动代码页 (ACP),可能是Windows 1252. 在 UNIX/Linux 和 z/OS 上,它可能与控制台/终端相同(Windows 是这里的奇怪系统,它具有不同的控制台编码和区域设置编码默认值)。
回到那个示例代码。该 UTF-8 编码ö字符(U+00F6,{LATIN SMALL LETTER O WITH DIAERESIS},编码为0xC3 0xB6)的预期或期望行为是什么?对于写入控制台的 Windows,要正确显示字符,需要将编码序列0x94转码为0xF6. 对于 UNIX/Linux,可能应该传递序列。对于 z/OS,可能需要将其转码为0xCC. 但是在所有这些系统上,这些默认值都是可配置的(例如,通过LANG环境变量)。
假设转码到运行时确定的编码是所需的行为,那么应该如何处理转码错误?例如,如果目标编码缺少 的表示会发生什么ö?如果存在格式错误的 UTF-8 序列怎么办?应该printf停止并报告错误吗?应该std::cout抛出异常吗?或者应该使用实现定义的字符,例如 U+FFFD {REPLACEMENT CHARACTER} 还是?替换?
如果std::cout充满了std::codecvt刻面会发生什么?据推测,该方面希望传入的文本采用特定的编码。UTF-8 文本在呈现给构面之前是否应该转码为执行字符集、语言环境相关编码或控制台/终端编码之一?如果有,是哪一个?实现是否应该知道流是否连接到控制台/终端?如果程序员想要覆盖默认值,例如,始终编写 UTF-8,该怎么办?
这些是相当困难的问题,我们没有很好的答案。 std::u8out有人建议将其作为显式选择加入 UTF-8 的一种方式,但不能解决预期的标准输出编码问题、codecvt方面问题以及其他 iostreams 问题(如隐式语言环境相关格式)。
就个人而言,为了在未来提供良好的 Unicode 支持,我认为我们将不得不投资替代 iostreams 1) 提供字节输出,文本支持分层,2) 编码感知(在文本层中) ), 3) 与语言环境无关(但显式选择支持语言环境相关格式,如std::format),4) 比 iostreams 性能更高。
SG16 想听听您的想法和建议。有关联系信息,请参阅https://github.com/sg16-unicode/sg16。
printf不是由 C++20 本身定义的;C++20 通过引用包含 C 标准库。它可能会引用 C18,但这基本上等于 C11(没有新功能;只是修复了缺陷报告)。