初学者在Windows平台上进行C/C 语言(中文)程序开发时,有时会遇到编译报错、在控制台运行时显示中文乱码的问题。
本文就此类问题进行描述、展开原因分析,然后给出解决方法。
本次分享内容的目录如下:
基本概念(字符集、字符编码、代码页、GBK、UTF-8)
问题描述(示例源码、编译报错、中文乱码)
原因分析(编码环节简介、原因分析)
解决方法(解决思路、编译报错解决、中文乱码解决)
结束语
1. 基本概念
本文会涉及到如下基本概念:
1.1 Charset(字符集)Charset(字符集):是一个系统支持的所有抽象字符的集合。字符是各种文字和符号的总称,包括各国家文字、标点符号、图形符号、数字等。常见的字符集有:ASCII字符集、Unicode字符集等。
计算机要准确的处理各种字符集文字,需要进行字符编码,以便计算机能够识别和存储各种文字。
1.2 Character Encoding(字符编码)Character Encoding(字符编码)用于为指定集合中某一对象(如电脉冲、比特模式等),以便文本在计算机中存储和通过通信网络的传递。字符编码就是将符号转换为计算机可以接受的数字系统的数。常见的例子:将拉丁字母表编码成ASCII。
1.3 CodePage(代码页)注:术语字符编码(Character Encoding)、字符映射(Character Map)或者代码页(CodePage),在历史上往往是同义概念,即字符表(repertoire)中的字符如何编码为码元的流(stream of code units)–通常每个字符对应单个码元。
CodePage(代码页)是字符编码的别名,也称内码表,是特定语言的字符集的一张表。
- OEM(IBM PC)代码页:指计算机的BIOS所支持的字符集编码。最具代表性的是"代码页437(IBM PC或MS-DOS )"。
- Windows(ANSI)代码页:微软针对不同的使用地区与国家,定义了一系列的支持不同语言字符集的代码页。最具代表性的是代码页WINDOWS-1252 (实现了ISO-8859-1)。
注:Windows代码页最初是根据ANSI草案实现的,这个草案最终成为ISO 8859-1。这是Windows代码页被称作ANSI的缘由。
本文涉及到的两个重要代码页介绍如下:
- 代码页936:该代码页对应的是GBK编码。既是OEM代码页,也是ANSI代码页。
- 代码页65001:该代码页对应的是UTF-8编码。
Windows平台上的GUI程序使用ANSI代码页,而在控制台程序使用OEM代码页(以便向后兼容)。
在Windows系统中的命令行窗口可以通过chcp命令来显示当前代码页(如Windows 7 简体中文操作系统上默认的代码页是936):
C:> chcp
活动代码页: 936
也可以通过在chcp命令后带一个具体整数参数(代码页数值)来临时改变命令行窗口的当前代码页(如临时修改为UTF-8对应的65001):
C:> chcp 65001
Active code page: 65001
1.4 GBK(汉字内码扩展规范)
GBK(英文全称:Chinese Internal Code Extension Specification,中文全称:汉字内码扩展规范)是对GB2312-80的扩展,也就是代码页936的扩展(之前代码页936和GB2312-80一模一样),最早实现于Windows 95简体中文版。
GBK总体编码范围为0x8140~0xFEFE,首字节在 0x81~0xFE 之间,尾字节在 0x40~0xFE 之间,剔除 xx7F 一条线。GBK共收录21886个汉字和图形符号,其中汉字(包括部首和构件)21003个,图形符号883个。
后续国家标准GB18030技术上兼容GBK。
1.5 UTF-8注:微软Windows安排给GBK的代码页是936,所以编码格式WINDOWS-936其实就是GBK。
UTF-8(8-bit Unicode Transformation Format)是一种针对 Unicode 的可变长度字符编码。它可以用一至四个字节对 Unicode字符集中的所有有效编码点进行编码,属于Unicode 标准的一部分。
自2009年以来 UTF-8一直是互联网上使用最广的一种编码方式。
2. 问题描述
初学者在Windows平台上进行C/C 语言(中文)程序编程开发时,有时会遇到编译报错、在控制台执行时显示中文乱码的问题。
2.0 示例源码下面用于示例的一个C语言源代码文件(功能:从控制台显示一段中英文信息。)
#include <stdio.h>
int main(void)
{
printf("
");
printf(" Hello, C语言开发者!
");
printf("
");
return 0;
}
2.1 编译报错
第一类问题是:在编译时发现报错,报错信息如下:
hello.c: In function 'main':
hello.c:6:12: error: converting to execution character set: Illegal byte sequence
printf(" Hello, C语言开发者!
");
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
2.2 中文乱码
第二类问题是:能顺利通过编译生成可执行文件,但该可执行文件在Windows控制台上运行时显示中文乱码,如下图示:
或:
3. 原因分析
Windows平台C/C 语言(中文)程序编译报错、在控制台执行时显示中文乱码一般都是由于编码不一致所引起的。
3.1 编码环节简介首先,我们来看看在 Windows 平台上开发运行一个C/C 语言程序的全过程(源文件编辑、编译、运行)中主要涉及的编码环节有哪些?
环节一、源代码保存时的字符编码
- 描述:指编辑器在保存源代码文件所使用的字符编码。
- 默认编码:Windows平台上默认是保存为Windows本地编码,即WINDOWS-936代码页,也就是GBK编码。
- 编码设置:可以通过编辑器设置来更改源文件保存编码,如保存为UTF-8编码。
环节二、编译器编译时的输入文件(源文件)字符编码
- 描述:GCC编译器编译时对输入的源码文件解析时用的字符编码。
- 默认:GCC编译器编译时对输入文件默认是按照UTF-8编码解析的。
- 编码设置:可以通过设置编译器选项-finput-charset=<charset>来指定编译器用什么编码解析输入的源文件。
- 示例:-finput-charset=GBK
环节三、编译器编译好的输出文件(可执行文件)字符编码
- 描述:GCC编译器编译好的输出文件(可执行文件)所用的字符编码。
- 默认:GCC编译器默认为UTF-8编码。
- 编码设置:GCC编译器可以通过设置-fexec-charset=<charset>选项来指定编译器用什么编码显示输出执行文件。
- 示例:-fexec-charset=GBK
环节四、控制台使用的字符编码
- 描述:控制台在显示所用的编码。
- 默认:Windows平台控制台默认使用WINDOWS-936代码页(即GBK编码);Linux控制台默认使用UTF-8编码。
- 编码设置:Windows平台可以通过注册表编辑器来指定控制台用什么编码显示输出执行文件。
Windows平台C/C 语言(中文)程序编译报错、在控制台执行时显示中文乱码一般都是由于编码不一致所引起的。
3.2.1 编译报错原因分析从上图可以很清晰的看出编译报错的原因是在环节一与环节二两处的编码不一致(如下)所引起的:
(一)上图中的1与4的组合(源文件保存为UTF-8编码,但GCC编译器对输入文件-源文件设置的是按GBK编码解析)
(二)上图中的2与3的组合(源文件保存为GBK编码,但GCC编译器对输入文件-源文件设置的是按UTF-8编码解析)
3.2.2 中文乱码原因分析从上图可以很清晰的看出中文乱码的原因是在环节三与环节四两处的编码不一致(如下)所引起的:
(一)上图中的5与8的组合(GCC编译器对输出执行文件设置的是UTF-8编码,但Windows控制台是GBK编码)
(二)上图中的6与7的组合(GCC编译器对输出执行文件设置的是GBK编码,但Windows控制台是UTF-8编码)
4. 解决方法4.1 解决思路
通过上述原因分析,已经发现了编译报错和中文乱码的问题根源所在:前后环节的编码不一致造成。
既然问题根源找到了,那么解决思路也就迎刃而解了(如下图示):
一、在环节一和环节二之间保持两者编码的一致性(1和3组合,或2和4组合)进而解决编译报错问题;
二、在环节三和环节四之间保持两者编码的一致性(5和7组合,或6和8组合)进而解决中文乱码问题。
4.2 编译报错解决针对编译报错的两种情形(1和4组合、2和3组合)具体解决办法是:
4.2.1 方法一(1和3组合)修改源文件编码为UTF-8编码,以跟GCC编译器对输入文件-源文件默认UTF-8编码解析保持一致。
修改源文件编码为UTF-8编码的具体步骤如下:
- Step1:通过执行Code::Blocks软件的菜单栏【设置】下的【编辑器】子菜单项,进入“编辑器配置”窗口。
- Step2:点击左侧【常规设置】按钮(上图标号1处),继续点击右侧的【编码设置】选项卡(上图标号2处)
- Step3:在使用编码右侧的下拉框中选择【UTF-8】(上图标号3处)
- Step4:选中【设为默认的编码方式(忽略C::B的自动检测)】(上图标号4处)
- Step5:点击右下角的【确定】按钮,完成编辑器编码设置。
- Step6:然后将编辑器内的源文件稍加修改重新保存(保险起见,可以重启 code::Blocks软件以确保源文件编码生效)。
4.2.2 方法二(2和4组合)
修改源文件编码为GBK编码,将GCC编译器对输入文件-源文件设置为是按GBK编码解析。
一、修改源文件编码为GBK编码的具体步骤
与上面类似(在下拉框中把UTF-8改为WINDOWS-936即可)。
二、修改编译器对输入源文件的解析编码为GBK编码的具体步骤如下:
- Step1:通过执行Code::Blocks软件的菜单栏【设置】下的【编译器】子菜单项,进入“编译器设置”窗口。
- Step2:点击左侧【全局编译器设置】按钮(上图标号1处),继续点击右侧的【编译器设置】选项卡(上图标号2处)
- Step3:再继续点击下方的【其他编译器设置】选项卡(上图标号3处)
- Step4:在下面的文本框中直接输入-finput-charset=GBK(上图标号4处)
- Step5:点击右下角的【确定】按钮,完成编译器输入编码设置。
验证:经过前面两种方法的设置,完成编码一致性后,再次进行编译,就已经可以成功通过了(如下图示)。
但是你会发现程序运行在控制台时显示中文乱码了。
此时再回想一下:源文件编码(GBK) 编译器输入设置编码(GBK) = 编译通过。但因为GCC编译器默认输出执行文件编码为UTF-8编码,同时Windows控制台默认是GBK编码,所以此时程序运行在控制台显示中文乱码逻辑上是正常的。
4.3 中文乱码解决针对中文乱码的两种情形(5和8组合、6和7组合)具体解决办法是:
4.3.1 解决方法一(6和8组合)设置GCC编译器对输出执行文件是GBK编码,跟Windows控制台默认GBK编码保持一致。
修改编译器对输出执行文件编码为GBK编码的具体步骤如下:
- Step1:通过执行Code::Blocks软件的菜单栏【设置】下的【编译器】子菜单项,进入“编译器设置”窗口。
- Step2:点击左侧【全局编译器设置】按钮(上图标号1处),继续点击右侧的【编译器设置】选项卡(上图标号2处)
- Step3:再继续点击下方的【其他编译器设置】选项卡(上图标号3处)
- Step4:在下面的文本框中直接输入-fexec-charset=GBK(上图标号4处)
- Step5:点击右下角的【确定】按钮,完成编译器输出编码设置。
4.3.2 解决方法二(5和7组合)
修改Windows控制台编码为UTF-8编码,以跟GCC编译器对输出执行文件默认UTF-8编码保持一致。
修改Windows控制台编码为UTF-8编码的具体步骤如下:
- Step1:通过快捷键Win R,弹出的【运行】窗口中,执行regedit命令,然后点击【确定】按钮打开“注册表编辑器”窗口。
- Step2:在“注册表编辑器”窗口中依次点击【计算机】(下图标号1)、【HKEY_CURRENT_USER】(下图标号2)、【Console】(下图标号3)
- Step3:在右侧选中【CodePage】项,然后双击弹出“编辑 DWORD(32位)值”窗口,依次选择【十进制】(下图标号1处)、把“数值数据”下的 936 修改为 65001(下图标号2处)。
- Step4:点击上图【确定】按钮,完成修改(如下图示)。
- Step5:按【快捷键F5】进行刷新生效。
注1:如果要恢复原数值只需重复同样的步骤,把65001修改为936即可。
注2:上面方法面向所有的控制台(如:Windows默认CMD控制台、CodeBlocks控制台、DevCpp控制台、Git CMD控制台等)生效。
注3:如果只需针对特定控制台生效,可以在本步骤基础上,再往下一层,选中具体控制台(如【C:_Develop_CodeBlocks_cb_console_runner.exe】),然后通过鼠标右键菜单新建一个【DWORD(32位)值】,该数值名称设为【CodePage】,数值数据设为【65001】(十进制)。然后【F5】刷新即可生效。
验证:经过上面两种方法的设置,完成编码一致性后,再次在控制台运行软件时就已经是正常显示中英文了(如下图示):
注:本文虽是以Code::Blocks集成开发环境为例进行讲解,但其原理针对Windows平台上C语言程序运行的其他控制台(如Windows默认CMD控制台、Git CMD控制台等)也是适用的。
结束语
相信各位 C 语言初学者们阅读完本文后,应该已经对 Windows 平台C语言(中文)程序在编译时报错的原因及解决办法、在控制台运行时显示中文乱码的原因及解决办法已经有了比较基本的了解掌握,此类问题将不再困扰,接下来就可以愉快地学习其他 C 语言知识了。
希望本文能对您有所帮助!喜欢的话就点个赞加关注支持一下哈:)
,