VSCode + GCC编译器(MinGW)开发环境中文字符乱码问题踩坑与解决办法

目录

    问题背景

    在较长一段时间里,C/C++开发者所使用的集成开发环境(IDE)要么是比较重量级的VS(Visual Studio),要么是Codeblocks·、·Visual C++ 6.0等轻量级IDE,又或者是诸如notepad++、sublime text等文本编辑器+GCC编译器+命令行工具的组合式开发环境。这几种开发方式要么太过庞大比较吃硬件资源,比如VS动辄就要占用几十个G的硬盘空间,要么虽然轻量但是没有友好的代码提示和自动化的编译链接运行过程,开发体验并不是很友好。

    近几年来,随着VSCode(Visual Studio Code)的流行,越来越多的开发者选择以此来作为个人的集成开发环境。使用VSCode开发C/C++程序可以下载安装VSCode官方的C/C++ for Visual Studio Code插件实现开发过程中的代码提示、调试、运行等功能,但是需要自行安装C/C++编译器,笔者是用的是GCC编译器MinGW。具体开发环境的搭建过程在此不作讲解,本文关注点在于开发过程中遇到的中文字符相关的乱码问题。

    问题描述

    测试代码

    1. 英文字符串文本文件 es_src.txt
    Chinese
    
    1. 中文字符串文本文件 ch_src.txt
    中文
    
    1. main.c
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    

    int main()
    {
    char str_es[] = "Chinese";
    char str_ch[] = "中文";
    char str[30];

    <span class="hljs-comment">// 读英文字符串的文本文件测试</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"读文件测试:\n"</span>);
    FILE *fpr_es = fopen(<span class="hljs-string">"es_src.txt"</span>, <span class="hljs-string">"r"</span>);
    <span class="hljs-keyword">while</span> (fgets(str, <span class="hljs-number">30</span>, fpr_es) != <span class="hljs-literal">NULL</span>)
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"strcmp(%s, %s)=%d\n"</span>, str_es, str, <span class="hljs-built_in">strcmp</span>(str_es, str));
    }
    fclose(fpr_es);
    
    <span class="hljs-comment">// 直接打印含中文字符串测试</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入英文字符串“Chinese”:\n"</span>);
    <span class="hljs-comment">// 读入英文字符串</span>
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%s"</span>, str);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"直接打印测试:\n"</span>);
    <span class="hljs-comment">// 直接打印英文字符串</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"str=%s\n"</span>, str);
    <span class="hljs-comment">// 与英文字符串常量进行比较</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"strcmp(%s, %s)=%d\n"</span>, str_es, str, <span class="hljs-built_in">strcmp</span>(str_es, str));
    
    <span class="hljs-comment">// 英文字符串写入文件测试</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"写文件测试:\n"</span>);
    FILE *fpw_es = fopen(<span class="hljs-string">"es_tar.txt"</span>, <span class="hljs-string">"w"</span>);
    <span class="hljs-built_in">fprintf</span>(fpw_es, <span class="hljs-string">"%s\n%s\n"</span>, str_es, str);
    fclose(fpw_es);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"写入完成!\n"</span>);
    
    <span class="hljs-comment">// 读中文字符串的文本文件测试</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"读文件测试:\n"</span>);
    FILE *fpr_ch = fopen(<span class="hljs-string">"ch_src.txt"</span>, <span class="hljs-string">"r"</span>);
    <span class="hljs-keyword">while</span> (fgets(str, <span class="hljs-number">30</span>, fpr_ch) != <span class="hljs-literal">NULL</span>)
    {
        <span class="hljs-built_in">printf</span>(<span class="hljs-string">"strcmp(%s, %s)=%d\n"</span>, str_ch, str, <span class="hljs-built_in">strcmp</span>(str_ch, str));
    }
    fclose(fpr_ch);
    
    <span class="hljs-comment">// 直接打印中文字符串测试</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"请输入中文字符串“中文”:\n"</span>);
    <span class="hljs-comment">// 读入中文字符串</span>
    <span class="hljs-built_in">scanf</span>(<span class="hljs-string">"%s"</span>, str);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"直接打印测试:\n"</span>);
    <span class="hljs-comment">// 直接打印中文字符串</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"str=%s\n"</span>, str);
    <span class="hljs-comment">// 与中文字符串常量进行比较</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"strcmp(%s, %s)=%d\n"</span>, str_ch, str, <span class="hljs-built_in">strcmp</span>(str_ch, str));
    
    <span class="hljs-comment">// 中文字符串写入文件测试</span>
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"写文件测试:\n"</span>);
    FILE *fpw_ch = fopen(<span class="hljs-string">"ch_tar.txt"</span>, <span class="hljs-string">"w"</span>);
    <span class="hljs-built_in">fprintf</span>(fpw_ch, <span class="hljs-string">"%s\n%s\n"</span>, str_ch, str);
    fclose(fpw_ch);
    <span class="hljs-built_in">printf</span>(<span class="hljs-string">"写入完成!\n"</span>);
    
    system(<span class="hljs-string">"pause"</span>);
    <span class="hljs-keyword">return</span> <span class="hljs-number">0</span>;
    

    }

    测试结果

    1. 控制台输出结果 可以看到 (a) 从文件中读取英文字符串并打印可以正常显示;直接打印英文字符串常量和直接打印从键盘读入的英文字符串均正常显示,使用strcmp进行比较结果为0。 (b) 从文件中读取中文字符串并打印可以正常显示;直接打印中文字符串常量可以正常显示,但是没有显示出从键盘读入的中文字符串,使用strcmp进行比较结果也不为0。

      image

    读文件测试:
    strcmp(Chinese, Chinese)=0 
    请输入英文字符串“Chinese”:
    Chinese
    直接打印测试:
    str=Chinese
    strcmp(Chinese, Chinese)=0
    写文件测试:
    写入完成!
    读文件测试:
    strcmp(中文, 中文)=0      
    请输入中文字符串“中文”:  
    中文
    直接打印测试:
    str=
    strcmp(中文, )=1
    写文件测试:
    写入完成!
    Press any key to continue . . .
    
    1. 英文字符串文本文件 es_tar.txt 英文字符串常量和从键盘读入的英文字符串均正常写入到文件中。
    Chinese
    Chinese
    

    1. 中文字符串文本文件 ch_tar.txt 中文字符串常量正常写入到文件,而从键盘读入的中文字符串写入到文件中的是乱码
    中文
    
    

    现象描述

    在使用VSCode + MinGW作为集成开发环境时,在不修改默认设置的情况下执行有中文字符的字符串操作时,通常会遇到以下几个问题:

    1. 直接打印含中文字符的字符串常量,比如printf("中文")或者printf("%s", "中文"),均可正常显示;但是打印由键盘读入的含中文字符的字符串时,如scanf("%s", str); printf("%s", str);,含中文字符的字符串str无法正常显示(不显示,或者显示为乱码)。
    2. 在读文件操作中,可以成功读入文本文件中的中文字符串,并且与中文字符串常量比较结果相等;但是在写文件操作中,写入文件的中文字符串常量能正常显示,但是由键盘读入的中文字符串则无法正常显示(不显示,或者显示为乱码)。

    简而言之,从键盘读入的中文字符串无法正常显示和写入文件

    问题分析

    已知信息:

    1. Windows(中文)默认的字符集是Windows-936(GBK)。
    2. 默认配置下,VSCode使用其内置集成终端运行编译后的exe可执行文件,使用chcp命令可知此终端使用的字符集编码是65001,即UTF-8编码。
    3. 默认配置下,VSCode中新建的文件使用的编码也是UTF-8。
    4. 默认配置下,GCC编译器MinGW的内部默认编码是UTF-8。 可能的原因: 由键盘读入的中文字符串使用的是GBK编码,但是程序运行过程中使用的都是UTF-8编码。

    解决方案

    既然读入的中文字符是GBK编码无法修改,那就把其他相关的地方全都改成gbk编码即可。

    修改默认配置

    1. 已经存在的文件全部使用gbk编码重新保存。

    image

    image

    2. 在工程目录下新建.vscode目录,如果已存在则跳过此步骤。
    3. 在.vscode目录中新建settings.jsonlaunch.json两个文件,已有则跳过。
    4. settings.json文件添加以下内容,使文件全部变成gbk编码:
    {
        "files.encoding": "gbk"
    }
    
    5. launch.json中修改以下内容,使用外置控制台运行编译后程序:
    {
        "configurations": [
            {
                ...
                "externalConsole": true,
                ...
            }
        ],
        "version": "2.0.0"
    }
    

    修改后测试代码的运行结果

    1. 控制台输出

      image

    读文件测试:
    strcmp(Chinese, Chinese)=0
    请输入英文字符串“Chinese”:
    Chinese
    直接打印测试:
    str=Chinese
    strcmp(Chinese, Chinese)=0
    写文件测试:
    写入完成!
    读文件测试:
    strcmp(中文, 中文)=0
    请输入中文字符串“中文”:
    中文
    直接打印测试:
    str=中文
    strcmp(中文, 中文)=0
    写文件测试:
    写入完成!
    请按任意键继续. . .
    
    1. es_tar.txt
    Chinese
    Chinese
    

    1. ch_tar.txt
    中文
    中文
    

    以上为全部内容,欢迎批评指正。

    posted @ 2024-01-25 23:26  程序员偏安  阅读(211)  评论(0编辑  收藏  举报  来源