如何在 C 中使用 printf 和 scanf 处理 char16_t 或 char32_t?

How to handle char16_t or char32_t with printf and scanf in C?

如果我写:

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 �”。

我已经以 HEX 格式给出了值 symbol = 0x0001F34C 还有其他方法可以解决这个问题,这就是我如何知道检查以下 c 中的代码我们不能使用 %c 或打印符号只有 printf here is explain why to use wchar_t instead of char char 有 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 

检查以下 link , UNICODE of emoji banana , char32_t

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

C 语言实际上有两种编码方式 - locale dependent 多字节字符表示和宽字符表示。

Is there something wrong here?

您在源文件中键入的 '' 字符 被编译器解释为某个特定于实现的值。 Gcc 将使 </code> 成为 UTF-8,然后 <a href="https://gcc.gnu.org/onlinedocs/cpp/Implementation-defined-behavior.html#Implementation-defined-behavior" rel="nofollow noreferrer">gcc preprocessor</a> 会将值左移,因此 <code>'' 等于 (int)0xF09F8D8C on gcc - 多字符文字的行为 'something' 是实现定义的。然后将该字符的值赋给char32_t。这根本不是 UTF-32 值。

How can I print char16_t and char32_t characters onto stdout?

将它们转换为多字节字符串。然后用 %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);
}

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

which format specifier should I use to get char16_t / char32_t input from scanf?

None,还有none。您应该使用 wchar_t 或纯 char 字符串以用户在其语言环境中指定的编码读取字符。然后你可以根据需要转换 to/from char16_tchar32_t 。如果你想专门读取 UTF-32 字符,那么你必须自己编写它以确保你的代码读取 UTF-32 个字符。我推荐 libunistring.