关于C#:UTF8控制台输出:MultiByteToWideChar vs mbsrtowcs

UTF8 console output: MultiByteToWideChar vs mbsrtowcs

我想从UTF-8文件中读取一小行并将其显示在Windows控制台中。

我成功使用WinByte函数的MultiByteToWideChar:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void mbtowchar(const char* input, WCHAR* output) {
  int len = MultiByteToWideChar(CP_UTF8, 0, input, -1, NULL, 0);
  MultiByteToWideChar(CP_UTF8, 0, input, -1, output, len);
}

void main() {
  setlocale(LC_ALL,"");
  char in[256];

  FILE* file = fopen("data.txt","r");
  fgets(in, 255, file);
  fclose(file);

  mbtowchar(in, out);
  printf("%ls",out);
}

...但是我使用ISO mbsrtowcs函数失败(非ASCII字符被弄乱了):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void main() {
  setlocale(LC_ALL,"");
  char in[256];
  wchar_t out[256];

  FILE* file = fopen("data.txt","r");
  fgets(in, 255, file);
  fclose(file);

  const char* p = in;
  mbstate_t mbs = 0;
  mbsrt, &am, &mbs);

  printf("%ls",out);
}

我对mbsrtowcs是否做错了事,或者这两个功能之间有重要区别? 是否可以使用ISO功能在Windows控制台中可靠地打印UTF-8? (假定已安装匹配的控制台字体。)

注意:我使用MinGW gcc编译器。 C ++对我而言是不得已的解决方案,我想继续使用C。


mbsrtowcs的"错误"是它将系统定义的8位字符(char)可变宽度编码转换为"宽"字符(wchar_t)的固定宽度数组。 今天,宽字符已被理解为Unicode代码点,但是"多字节"并不一定意味着UTF-8。 实际上,在Windows上,它指的是亚洲文字的各种pre-Unicode编码。 令人沮丧的是,Windows根本不支持UTF-8作为本机的"多字节"编码,而且显然永远也不会。

因此,尝试使用mbsrtowcs解释UTF-8的尝试注定在Win32上失败。 您将必须像第一个代码片段一样使用MultiByteToWideChar,或切换到将UTF-8转换为UTF-16的其他方法。 (由于UTF-8和UTF-16都编码UCS代码点,因此,如果您的目标是避免依赖专有扩展,则甚至可以编写自己的简单例程来执行此操作。)