无法读取和回显C中的unicode输入

时间:2019-01-24 12:03:52

标签: c unicode wchar-t wchar

我编写了以下代码:

#include <stdio.h>
#include <wchar.h>

int main() {
    wchar_t wc[80];
    wscanf(L"%ls", &wc);
    wprintf(L"%ls", wc);
    return 0;
}

that's what i get as a result

我的终端支持在Linux上使用gcc 8.2.1编译的Unicode。

1 个答案:

答案 0 :(得分:1)

这是程序的固定版本:

#include <stdlib.h>
#include <locale.h>
#include <stdio.h>
#include <wchar.h>

int main(void)
{
    wchar_t  ws[80];

    if (!setlocale(LC_ALL, ""))
        fprintf(stderr, "Warning: The C library does not support your current locale.\n");
    if (fwide(stdin, 1) < 1)
        fprintf(stderr, "Warning: The C library does not support wide standard input for your current locale.\n");
    if (fwide(stdout, 1) < 1)
        fprintf(stderr, "Warning: The C library does not support wide standard output for your current locale.\n");

    if (wscanf(L"%79ls", ws) < 1) {
        fprintf(stderr, "No input.\n");
        exit(EXIT_FAILURE);
    }

    wprintf(L"%ls\n", ws);

    return EXIT_SUCCESS;
}

setlocale()调用告诉C库使用当前配置的语言环境。如果不这样做,则C库将使用其默认语言环境(C / POSIX),通常使用ASCII字符集(而不是UTF-8)。

fwide(stdin, 1)fwide(stdout, 1)调用告诉C库,您将使用标准输入的宽输入函数,以及标准输出的宽输出函数。如果C库对于当前语言环境不支持,则它们将返回-1;否则,它们将返回-1。我认为当前在Windows中基于UTF-8的语言环境会发生这种情况,因为Microsoft希望程序员为此使用其专有扩展名。

不需要fwide()调用,因为C库将根据您用于每个流的第一个函数进行猜测。我确实建议显式使用它们,以便用户知道其当前配置或C库支持是否存在某些错误/错误/不受支持。毕竟,这只是几行。

扫描字符串时,应始终在模式中包括最大允许长度(紧随%之后)。由于C字符串的末尾为nul字符(窄字符串为'\0',宽字符串为L'\0'),因此缓冲区必须至少长一个。由于ws是由80个宽字符组成的数组,因此wscanf()可以在其中扫描多达79个字符的字符串。

所有扫描功能(scanf()wscanf()fscanf()fwscanf()等)返回成功转换的次数,或EOF / WEOF。例如,如果用户运行true | ./thisprogram,则标准输入中没有输入,并且wscanf()调用将返回WEOF。除了少数几个例外(使用抑制的转换来消耗/跳过数据,或使用%n进行的转换)之外,您将需要检查返回值。如果未在上面的示例(true | ./thisprogram)中检查返回值,最终将打印出未初始化的宽字符缓冲区。哪一个不好它可以不打印任何内容,打印垃圾或使程序崩溃:这是未定义的行为。

(要记住,如果转换失败,失败的部分将保留在输入中;它不会被消耗或丢弃。它只是放在那儿,除非您使用它。)

如果某些shell没有以换行符结尾,则在该行的末尾添加一个%字符。之后,其他shell会立即发出自己的提示。那不是一个错误,只是看起来很奇怪。因此,最好在输出末尾添加换行符。

默认情况下,标准输出也是行缓冲的。例如,在上述程序中,使用wprintf(L"foo")不会 not 表示输出宽字符串foo;它通常仅由标准C库缓冲,并在一段时间后输出。您可以使用fflush(stdout);告诉标准库为特定流输出其缓冲区中的所有内容,例如标准输出。这适用于正常/窄流和宽流。但是,C库会在程序退出时自动刷新缓冲区。