【问题标题】:Can't use "wscanf" while using "_setmode (_fileno(stdin), _O_U16TEXT)"使用“_setmode (_fileno(stdin), _O_U16TEXT)”时不能使用“wscanf”
【发布时间】:2021-12-31 08:39:11
【问题描述】:

我正在尝试在我的程序中实现西里尔字符的输入和输出。我读了this 回答如何实现它(它在俄语上)。它说使用_setmode (_fileno (stdin), _O_U16TEXT); 应该可以很好地处理使用wscanfwcin 的UTF-8 字符。

这是一个不使用 _setmode 的小型 wchar 输入示例:

#include <stdio.h>

int main()
{
    int input = -1;

    wprintf (L"Enter a number: ");
    wscanf  (L"%d", &input);
    wprintf (L"%d", input);

    return 0;
}

输入数字时效果很好:输入数字被写入控制台。但是当我尝试使用 _setmode 时:

#include <stdio.h>
#include <fcntl.h>
#include <io.h>

int main()
{
    int input = -1;

    _setmode(_fileno(stdin),  _O_U16TEXT);

    wprintf (L"Enter a number: ");
    wscanf  (L"%d", &input);
    wprintf (L"%d", input);

    return 0;
}

然后wscanf 什么都不做 - 它返回 0,并且输入变量没有改变,所以到控制台的输出总是 -1。

我不明白为什么会这样。 _fileno (stdin) 返回 0,因为它应该为标准输入做。 _setmode 返回 16384,所以它不是 -1,这应该意味着它可以正常工作。另外,我的源文件是用 UTF-8 编码的。

【问题讨论】:

  • 添加#include &lt;io.h&gt;会怎样?
  • @AdrianMole 使用 #include &lt;io.h&gt; 没有任何改变。我将通过我使用 C++ Code::Blocks 项目将语言标签更正为“C”(哦,你做到了,好吧),可能它包括 io.h 本身。
  • 标准输入数据从何而来?管道?输入的编码是什么?
  • @Anders 对不起,如何查看输入的编码?我不确定我是否理解管道输入是什么,但我想我不会使用它,我只是将数据从键盘输入到控制台。
  • 如果您使用键盘输入,则输入不会重定向(不是管道也不是文件)。这对于重现问题很重要。

标签: c windows mingw


【解决方案1】:

“应该可以使用 wscanf 或 wcin 处理 UTF-8 字符”

(错字?)Windows 不支持 UTF-8 输入(至少在 Windows 10 和更早版本中不支持,仅支持 UTF8 输出)_setmode 确实启用了 UTF-16 输入。

IDE 可能使用自己的控制台,该控制台与宽字符不兼容。确保从 Windows 运行命令提示符,并在 Windows 命令提示符下执行程序。

使用ReadConsoleW API 查看是否支持Unicode,或者直接使用该API 代替wscanf

为输入和输出启用 Unicode

_setmode(_fileno(stdin), _O_U16TEXT);
_setmode(_fileno(stdout), _O_U16TEXT);

【讨论】:

  • 这些函数在 C 运行时中,因此不严格绑定到 Windows 版本。相关:alfps.wordpress.com/2011/12/08/unicode-part-2-utf-8-stream-mode
  • 1.是的,一个错字,但在代码中:我正在尝试启用 UTF-8 输入,但我将使用 _O_U8TEXT。 2. 我尝试使用 MinGW 在 Dev-C++ 中编译相同的代码,我尝试使用 MinGW 自己编译它 - 没有任何改变。 3. 嗯,让我检查一下。 4. 使用这两条线不会改变任何东西。 所以,它适用于 _O_U8TEXT,但我仍然误解了我对 UTF-16 的使用的误解。
  • @Anders 我不确定你的意思。您发布的链接显示 UTF8 输入在 Windows 中不起作用。如果向下滚动到第 50 页,您会看到 ReadConsoleMultiByteToWideChar 的用法和已弃用的 codecvt。但如果 UTF8 工作正常,那么我为大家感到高兴。我不知道是什么问题。
  • @BarmakShemirani 但我注意到将 _O_U8TEXT 与 stdin 和 stdout 一起使用会产生另一个问题:它不允许我使用 wprintf (L"...") 输出西里尔字符。对标准输出使用 _O_U16TEXT 对标准输入使用 _O_U8TEXT 可以解决问题,但我确信这是对编码的错误使用。因此:两个流的 _O_U8TEXT 不适用于常量 L 字符串,_O_U16TEXT 不适用于 stdio 输入。我做错了什么?
  • 好像有两个问题。首先,“UTF16 输入”似乎不适用于 MinGW(它确实适用于 Visual Studio,我没有尝试过使用 MinGW)。你解决了第一个问题吗?其次,你有一个 UTF8 文件,你可以使用 MultiByteToWideChar 将 UTF8 转换为 UTF16,使用 wprintf。或者你可以设置SetConsoleOutputCP(CP_UTF8)/printf
猜你喜欢
  • 1970-01-01
  • 2019-07-01
  • 2011-11-15
  • 2017-05-17
  • 2021-01-08
  • 1970-01-01
  • 2016-09-19
  • 2020-04-07
  • 2013-04-27
相关资源
最近更新 更多