在Windows上使用MinGW和GCC编译器处理UTF-8字符

6

我在使用GCC编译器和Windows CMD时遇到了问题,因为无法正确地显示UTF-8字符。以下是我的代码:

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

int main()
{
  char caractere;
  int inteiro;
  float Float;
  double Double;

  printf("Tipo de Dados\tNúmero de Bytes\tEndereço\n");
  printf("Caractere\t%d bytes \t em %d\n", sizeof(caractere), &caractere);
  printf("Inteiro\t%d bytes \t em %d\n", sizeof(inteiro), &inteiro);
  printf("Float\t%d bytes \t\t em %d\n", sizeof(Float), &Float);
  printf("Double\t%d bytes \t em %d\n", sizeof(Double), &Double);

  printf("Caractere: %d bytes \t em %p\n", sizeof(caractere), &caractere);
  printf("Inteiro: %d bytes \t em %p\n", sizeof(inteiro), &inteiro);
  printf("Float: %d bytes \t\t em %p\n", sizeof(Float), &Float);
  printf("Double: %d bytes \t em %p\n", sizeof(Double), &Double);

  return 0;
}

然后我运行以下命令:

gcc pointers01.c -o pointers

我没有遇到任何编译错误,但是当我执行生成的文件(.exe)时,它不显示UTF-8字符:

Tipo de Dados   Número de Bytes    Endereço
Caractere   1 bytes      em 2686751
Inteiro 4 bytes      em 2686744
Float   4 bytes          em 2686740
Double  8 bytes      em 2686728
Caractere: 1 bytes   em 0028FF1F
Inteiro: 4 bytes     em 0028FF18
Float: 4 bytes       em 0028FF14
Double: 8 bytes      em 0028FF08

我应该怎么做来解决这个问题?谢谢。


这是Windows控制台的问题。有一些解决方法,但没有一个是完全可靠的,即在每种情况下都能正常工作。 - deviantfan
你知道有什么解决方法吗?即使有“但是”的情况下也可以。 - Henrique Dias
请查看此处的被接受的答案和前两条评论(回答):https://dev59.com/3XRC5IYBdhLWcg3wK9yV (好吧,它也不是非常详细...也许我可以在其他地方找到另一个链接...) - deviantfan
谢谢。它能工作,但似乎有很多“但是”……我希望在Windows 10中他们能改进这个。=D - Henrique Dias
那么...你想写答案吗?还是我应该给出我的答案?O.o - Henrique Dias
2个回答

8

可悲的是,Windows控制台对UTF-8支持非常有限且存在错误。

可以做的事情:将代码页设置为65001并使用支持它的字体之一,例如“Lucida Console”。代码页可以通过命令chcp或在C / C ++中使用函数SetConsoleOutputCP来设置;字体则通过SetCurrentConsoleFontEx设置。

然而,这里有一些主要(和次要)问题。首先是次要问题:

a)这些函数仅适用于一个会话,即如果您稍后再次运行程序,则必须再次设置它。理论上可以将其设置为默认值,但不建议这样做,因为它将影响所有控制台程序,并向它们引入下面的问题,即使它们没有与代码页相关的操作并且没有编写以缓解这些问题。

b)如果控制台不是由程序打开的,而是从现有控制台启动它,则它将影响之后运行的任何内容,直到关闭此控制台。因此,在您自己的程序退出之前,必须将其更改回默认值。

c)某些可用于控制台输入/输出的函数无法与CP65001正常工作。
(这是最严重的问题)

与Windows的整个UTF16部分不同,它部分地将UTF8视为任何1字节字符集,并且执行一些奇怪的操作,这些操作恰好符合1字节字符集的标准,但实现方式不同。

例如,如果使用大小为1调用fread,则应返回读取的字节数,但在Microsoft的实现中,它确实返回字符数(UTF16是一个例外,但不是UTF8)。对于任何正常的代码页,它都可以工作,因为1char = 1byte,但对于UTF8则不行...错误的返回值=>处理错误的数据

另一个例子,fflush可能会挂起(至少有报道称如此,没有检查)。等等。
而且它不仅影响标准C函数,还影响直接的Winapi调用。

d)由于c)的结果,所有带有UTF-8字符的批处理文件(除了正常的ASCII范围)在某些Windows版本中无法正常工作(没有检查每个版本,但很可能Win10仍然存在此错误。微软没有任何意图尽快解决它。)

以下是关于 C 和 D 的更多阅读材料:https://social.msdn.microsoft.com/Forums/vstudio/en-US/e4b91f49-6f60-4ffe-887a-e18e39250905/possible-bugs-in-writefile-and-crt-unicode-issues?forum=vcgeneral


只是一件小事,使用Cygwin编译带有重音符号的单词的C程序时,一切都运行得很完美。现在我需要使用TDM-GCC创建Go DLLs,但是这些单词上出现了错误。这可能也是编译器或其他什么问题,否则在Cygwin中它不会工作,我想。 - Edw590
为什么不在写入控制台之前将UTF-8转换为UTF-16呢? - JoelFan

0

我通常使用Sublime Text将源文件保存为DOS(CP437)格式,这样可以正常工作(至少对于小程序而言)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接