C 使用fread()和printf()读取和打印汉字?

C 使用fread()和printf()读取和打印汉字?,c,unicode,fread,chinese-locale,C,Unicode,Fread,Chinese Locale,我正在试着读一本内嵌的中文,我在这里找到了一些关于这个主题的问题,但没有任何适合我或适合我需要的。我正在使用中的fread()实现,但它不起作用。我正在运行Linux #define UNICODE #ifdef UNICODE #define _UNICODE #else #define _MBCS #endif #include <locale.h> #include <stdio.h> #include <wchar.h&

我正在试着读一本内嵌的中文,我在这里找到了一些关于这个主题的问题,但没有任何适合我或适合我需要的。我正在使用中的fread()实现,但它不起作用。我正在运行Linux

  #define UNICODE
  #ifdef UNICODE
  #define _UNICODE
  #else
  #define _MBCS
  #endif

  #include <locale.h>
  #include <stdio.h>
  #include <wchar.h>
  #include <string.h>
  #include <stdlib.h>
  int main(int argc, char * argv[]) {
         FILE *infile = fopen(argv[1], "r");
         wchar_t test[2] = L"\u4E2A";
         setlocale(LC_ALL, "");
         printf("%ls\n", test); //test
         wcscpy(test, L"\u4F60"); //test
         printf("%ls\n", test); //test
         for (int i = 0; i < 5; i++){
                 fread(test, 2, 2, infile);
                 printf("%ls\n", test);
         }
 return 0;
  }
程序输出:

个 
你
������ 
有人对这个问题有什么看法吗


编辑:还有,这就是我所有的代码,因为我不确定它在哪里失败。这里有一些东西,我测试以确保我可以打印与问题不完全相关的unicode wchars

您正在告诉
fread
在每次调用中读取两个2字节的值;但是,要读取的字符具有3字节UTF-8编码。通常,您需要将UTF-8流作为一个整体进行解码,而不是以固定大小的字节块进行解码。

如果您确实需要一次读取一个UTF-8(或者更确切地说是一个区域设置字符映射)文件,您可以使用
fscanf
,如下所示。但请注意,这是码点而不是字符,字符可能由多个码点组成,因为组合了码,并且某些码点绝对不可打印

#include <locale.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    FILE   *infile = fopen(argv[1], "r");
    wchar_t test[2] = L"\u4E2A";
    setlocale(LC_ALL, "");
    printf("%ls\n", test);  //test
    wcscpy(test, L"\u4F60");        //test
    printf("%ls\n", test);  //test
    for (int i = 0; i < 5; i++) {
        fscanf(infile, "%1ls", test);
        printf("%ls\n", test);
    }
    return 0;
}
#包括
#包括
#包括
#包括
#包括
int
main(int argc,char*argv[])
{
文件*infle=fopen(argv[1],“r”);
wchar_t test[2]=L“\u4E2A”;
setlocale(LC_ALL,“”);
printf(“%ls\n”,test);//test
wcscpy(test,L“\u4F60”);//test
printf(“%ls\n”,test);//test
对于(int i=0;i<5;i++){
fscanf(填充,“%1ls”,测试);
printf(“%ls\n”,测试);
}
返回0;
}

大多数情况下,您可能不需要使用区域设置功能,因为如果将UTF-8视为不透明编码,它通常就可以工作。这部分是因为所有非ASCII字符的组件字节在128..253范围内(不是打字错误,254和255未使用)另一部分是字节128..159始终是连续字节所有字符的开始字节都是160..253,这意味着错误只会中断一个字符,而不会中断流的其余部分。(好的,代码点vs字符只是想让您相信,将UTF-8划分为“字符”可能不会达到您想要的效果)

Windows还是Linux?如果是windows,请尝试以二进制
fopen(argv[1],“rb”)
的形式打开文件。是否可以从代码示例中删除行号?当我试图帮助您时,它们使代码难以执行。@user3386109不仅如此,您可能希望将其作为一个宽字符流打开。您需要检查文件的编码方式。(utf-8、utf-16、utf-32)?您需要检查您的文件是否包含BOM。
fread
仅适用于utf-16。在utf-8中,每个字符占用1到6个字节,因此您必须一次读取一个字节,直到获得完整字符。我无法理解如何将utf-8字符转换为printf的
wchar\t
。这是一个很好的答案,谢谢。几个小时后,我将尝试使用UTF-16输入instwad运行相同的程序。“代码点”的复杂性似乎不值得。UTF-16具有UTF-8所具有的所有问题,再加上一些问题,它对于任何操作系统都是一个糟糕的选择。例如“
#include <locale.h>
#include <stdio.h>
#include <wchar.h>
#include <string.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
    FILE   *infile = fopen(argv[1], "r");
    wchar_t test[2] = L"\u4E2A";
    setlocale(LC_ALL, "");
    printf("%ls\n", test);  //test
    wcscpy(test, L"\u4F60");        //test
    printf("%ls\n", test);  //test
    for (int i = 0; i < 5; i++) {
        fscanf(infile, "%1ls", test);
        printf("%ls\n", test);
    }
    return 0;
}