char8_t *的printf()格式字符是什么?

Che*_*tor 7 c c++ utf-8

还有 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_tprintf("%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)

要开始阅读此主题,可能需要这两篇论文

  1. http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2231.htm
  2. http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p1423r2.html

以该顺序。


我的主要DEVENV是VisualStudio 2019,同时包含VS随附的MSVC和CLANG 8.0.1。使用std:c ++ latest。开发人员机器为WIN10 [版本10.0.18362.476]

vit*_*aut 7

\n

char8_t * 的 printf() 格式字符是什么?

\n
\n

没有将打印char8_t*为字符串的格式说明符。从技术上讲,使用%s是一种未定义的行为,因为类型不匹配,clang 会警告您(https://godbolt.org/z/xcs9Wj):

\n
printf("%s", u8"\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!");\n
Run 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\n
Run Code Online (Sandbox Code Playgroud)\n

所以你唯一能做的就是将这样的字符串打印为指针,但这%p并不是很有用。

\n

iostream 也不支持char8_t字符串。例如,这不能在 C++20 中编译:

\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\n
Run Code Online (Sandbox Code Playgroud)\n

在大多数平台上,普通char字符串已经是 UTF-8,在带有 MSVC 的 Windows 上,您可以使用 /utf-8 进行编译,这将为您在主要操作系统上提供 Unicode 支持。

\n

对于可移植的 Unicode 输出,您可以使用 {fmt} 库,例如 ( https://godbolt.org/z/3ejsaG ):

\n
std::cout << u8"\xd0\x9f\xd1\x80\xd0\xb8\xd0\xb2\xd0\xb5\xd1\x82, \xd0\xbc\xd0\xb8\xd1\x80!";\n
Run 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!\n
Run Code Online (Sandbox Code Playgroud)\n

免责声明:我是 {fmt} 的作者。

\n

  • 非常感谢汤姆。虽然我们昨天需要解决方案,而不是 23 号。 (2认同)

Tom*_*ann 6

我是C++的char8_t P0482P1423提案以及 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

  • 我同意 UTF-8 如今对于任务至关重要,尽管我很想在 C++20 中提供更多支持,但这已不再是一种选择。我于 2016 年 11 月首次向委员会提交了“char8_t”,直到 2018 年 11 月才被接受。今年又召开了几次会议才使 P1423 委员会获得通过。改变并不总是像我们希望的那么快发生。 (4认同)
  • 我忘了提及。我们解决上述限制的短期计划 (C++23) 是提供显式编码、解码和转码接口,如 [P1629](https://wg21.link/p1629) 中所述。这将允许程序员根据需要在各种执行和 UTF 编码之间手动转码。 (3认同)
  • 亲爱的汤姆,我知道 P1629。这是好的并且合乎逻辑的。但。我需要的“唯一的东西”是完全实现并能够输出 u8 序列和单个元素的 `printf()`。即 `char8_t *` 和 `char8_t`。-- `u8` 自 2011 年开始出现。而 `char8_t` 是 C++20 关键字。尽管如此,似乎还没有必要的决定和实施。我可能认为 utf-8 现在是相当关键的任务。我认为整个 C++ 社区不能等到 2023 年才能完全决定 utf-8 并在标准 C++ 中实现。 (2认同)
  • 在我提供的答案中,我询问 `printf("%&lt;something&gt;", u8"text")` 的行为应该是什么。我不清楚。我怀疑您可能对应该发生的事情有意见,并且我进一步怀疑我们可以做出一些您会认为令人反感或有疑问的设计决策。您更喜欢什么行为?为什么? (2认同)
  • C++ 遵循 C 的“printf”及其相关规范。C++ 标准 *可能* 对这些函数提出额外的要求,但大多数 C++ 实现都遵循它们无法控制的 C 标准库的实现。对“printf”进行更改将有效地要求我们完成 WG14。WG14 至少三年内不会有新标准。因此,我们还需要一段时间才能看到“printf”的变化;假设我们能够就这些改变的内容达成一致。 (2认同)
  • 程序运行的环境不在标准的控制范围内,但程序如何与环境交互却在标准的控制范围之内。ISO C99 没有将 `%s` 格式说明符定义为用于输出 *ASCII* 字符串,而是输出最多但不包括 `NUL` 字符的“字符”(可能不是 ASCII)。Java 的“OutputStreamWriter”允许指定编码(默认为区域设置)。Python 3 更改了与 [PEP 538](https://www.python.org/dev/peps/pep-0538) 和 [PEP 540](https://www.python.org/dev/peps/pep -0540)。 (2认同)

MSa*_*ers 2

printf不是由 C++20 本身定义的;C++20 通过引用包含 C 标准库。它可能会引用 C18,但这基本上等于 C11(没有新功能;只是修复了缺陷报告)。

  • @PanagiotisKanavos“在 C++ 中,应该使用像 cout、wcout 这样的流”。直到它们被弃用,这可能很快就会发生。他们基本上已经坏了。20 年前看起来是个好主意的想法现在突然显得笨拙且不稳定。C++20 中已经有更好的格式化机制(std::format)。 (2认同)