【问题标题】:How to handle char16_t or char32_t with printf and scanf in C?如何在 C 中使用 printf 和 scanf 处理 char16_t 或 char32_t?
【发布时间】:2021-06-25 04:46:24
【问题描述】:

如果我写:

char a = 'A';
printf("%x %c", a, a);

它将产生输出“41 A”。 我写的时候也是这样

char32_t c = U'????';
printf("%x %c", c, c);  //even tried %lc and %llc

它将产生输出“1f34c L”而不是预期的“1f34c ????”!

这里有什么问题吗?如何将 char16_t 和 char32_t 字符打印到标准输出?

另外,我应该使用哪个格式说明符从 scanf 获取 char16_t / char32_t 输入?

char32_t c;
scanf("%c", &c); //????
printf("%x %c", c, c);

这将产生输出“f0 �”。

【问题讨论】:

  • 另一个问题中的this answer 有帮助吗?
  • @mediocrevegetable1 部分​​.. 但它太复杂了(使用 c32rtomb)。该工作没有简单的格式说明符吗?此外,它没有解释如何将 char32_t 与 scanf 一起使用。
  • @SouravKannanthaB 你在 Windows 上吗?
  • 嗯,我明白了。也许您可以使用wchar_t,但它在 Windows 上是 UTF-16,在 Linux 上是 UTF-32。除此之外,我不确定。我从未使用过char16_tchar32_t,也很少使用过wchar_t
  • char32_t c = '????'; =>char32_t c = U'????';

标签: c printf scanf char16-t char32-t


【解决方案1】:

我已经给出了HEX 格式symbol = 0x0001F34C 的值,还有其他方法可以解决这个问题,这就是我知道如何检查c 中的以下代码,我们无法使用%c 或仅使用printf here is explain why to use wchar_t instead of char @ 打印符号987654329@ 有 UTF-8 编码,而 wchar_t 有 UTF-32,这增加了它的范围

#include <stdio.h>
#include <wchar.h>
#include <locale.h>
int main() {
    setlocale(LC_CTYPE, "");
    wchar_t symbol = 0x0001F34C;
    wprintf(L"%x %lc\n",symbol,symbol);
}
output: 1f34c ?

检查以下链接 Printing a Unicode Symbol in CUNICODE of emoji bananachar32_t

【讨论】:

  • 对我来说,它正在打印1f34c ?。为什么会这样?
  • and wchar_t have UTF-32 在 Linux 上,wchar_t 在 Windows 上是 UTF-16。
  • 是的,在 Windows 上。但是 wchar_t 的 sizeof 是 4 个字节! (使用在线编译器)
  • @SouravKannanthaB printf("\xF0\x9F\x8D\x8C"); 检查这是否有效或这个 -> printf("\xD83C\xDF4C"); 因为我没有使用 Windows 我试图直接打印它
【解决方案2】:

char16_tchar32_t 没什么特别的。它们实际上只是uint_least16_tuint_least32_t。他们没有那么大的支持。它们的唯一用途基本上是 uU 文字。它们可能不是是 UTF-16 和 UTF-32 - 在假设它们是之前检查 __STDC_UTF_16____STDC_UTF_32__ 宏。只有非常基本的转换函数是标准的。在标准中,只有将char16_tchar32_t 转换为多字节编码并返回的函数。要对它们进行更多任何操作,您必须自己实现它。

C 语言实际上有两种编码 - 区域设置相关多字节字符表示和宽字符表示。

这里有什么问题吗?

您在源文件中键入的'?' 字符 被编译器解释为某个特定于实现的值。 Gcc 将使 ? 成为 UTF-8,然后 gcc preprocessor 将值向左移动,因此 '?' 等于 (int)0xF09F8D8C 在 gcc 上 - 多字符文字 @987654337 的行为@ 是实现定义的。然后将该字符的值分配给char32_t。这根本不是 UTF-32 值。

如何将 char16_t 和 char32_t 字符打印到标准输出?

将它们转换为多字节字符串。然后用%s打印出来。

#include <stdlib.h>
#include <uchar.h>
#include <stdio.h>
#include <wchar.h>
#include <limits.h>
#include <string.h>
#include <errno.h>
#include <locale.h>
int main() {
    setlocale(LC_ALL, "en_US.UTF-8");
    char32_t c = U'?';
    char buf[MB_LEN_MAX + 1] = {0};
    mbstate_t ps;
    memset(&ps, 0, sizeof(ps));
    c32rtomb(buf, c, &ps);
    printf("%s\n", buf);
}

打印数据取决于区域设置,因为打印是在用户指定的区域设置中完成的。默认语言环境是C,不支持UTF。所以首先你必须将你的语言环境设置为兼容 utf 的东西。然后拨打c32rtomb。请注意,流在第一次在glibc 中打印时会选择编码 - 请确保在对要使用的流执行任何操作之前调用setlocale

我应该使用哪个格式说明符从 scanf 获取 char16_t / char32_t 输入?

没有,没有。您应该使用wchar_t 或普通的char 字符串来读取用户在其语言环境中指定的编码的字符。然后,您可以根据需要与char16_tchar32_t 相互转换。如果您想专门读取 UTF-32 字符,则必须自己编写以确保您的代码读取 UTF-32 字符。我推荐libunistring

【讨论】:

  • MB_CUR_MAX 定义在哪里?我的编译器在 uchar.h 中没有找到它
  • 在我的代码中,我实际上在 '?' 前面加上了 U。我在这里打错了。
  • My compiler did not found it in uchar.h 应该在uchar.h。发布您的编译器、编译器设置、标准库版本。 char32_t 的支持在编译器中不是很好,而是使用外部库。
  • 您最后提供的解决方案代码对我不起作用。 c32rtomb 返回 -1。
  • 我的编译器 - x86-64 gcc 10.2 windows 64 位机器。
猜你喜欢
  • 2011-12-31
  • 2015-11-10
  • 2013-10-04
  • 1970-01-01
  • 2016-05-20
  • 2015-08-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多