我编写了以下代码:
#include <stdio.h>
#include <wchar.h>
int main() {
wchar_t wc[80];
wscanf(L"%ls", &wc);
wprintf(L"%ls", wc);
return 0;
}
我的终端支持在Linux上使用gcc 8.2.1编译的Unicode。
答案 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库会在程序退出时自动刷新缓冲区。