c++中文编码格式
c++程序中涉及到中文字符的输入输出以及其他操作经常会出现乱码。乱码主要是由于程序的源文件编码、可执行文件编码以及程序运行环境的编码不匹配导致。比如,c++源程序文件编码为GB18030, 在源程序中有一中文窄字符串常量,程序运行时输出该字符串常量,运行环境的系统编码为UTF8时,就会输出乱码。
一、程序相关的编码
1.程序源文件编码
程序源文件编码是指保存程序源文件内容所使用的编码方案,该编码方案可在保存文件的时候自定义。
通常在简体中文windows环境下,各种编辑器(包括visual studio)新建文件缺省编码都是GB18030,所以不特别指定的话,windows环境下的c++源文件的编码通常为GB18030(GB18030兼容GBK);在linux环境下,默认的为UTF-8编码。
2.c++程序内码
源程序编译后,c++中的字符串常量变成一串字节存放在可执行文件中,内码指的是在可执行文件中,字符串以什么编码进行存放。这里的字符串常量指的是窄字符(char)而不是宽字符(wchar_t)。宽字符通常都是以Unicode(VC使用UTF-16BE, gcc使用UTF-32BE)存放。
通常简体中文版的VC使用内码为GB18030,而gcc使用内码缺省为UTF-8,单可以通过-fexec-charset参数进行修改。(可以通过在程序中打印字符串中每个字节的16进制形式来判断程序使用的内码)。
3.运行环境编码
运行环境编码指的是,执行程序时,操作系统或终端所使用的编码。程序中输出的字符最终要转换为运行环境编码才能显示,否则就会出现乱码。
常用的简体中文版的windows环境编码是GB18030,linux下最常用的环境编码是UTF-8。
4.三种编码之间的关系
程序源文件【源文件编码】--->(编译器编译) ---->目标文件【程序内码】----> (运行后输出信息)---->输出【运行环境编码】
编译器需要正确识别源文件的编码,把源文件编译为目标文件,并把源文件中的以源文件编码的字符串转换为以程序内码编制的字符串保存在目标文件中。
如果源程序中的为窄字符串常量,则程序运行时,直接将目标文件中对应的内码字符串输出;若为宽字符串常量,则程序运行时c++标准库需要正确识别终端的运行环境编码,并把程序的输出转换为运行环境所使用的编码,以便正确显示。
二、c++宽窄字符
c++有窄字符char和宽字符wchar_t的区别,分别有一套相应的类和函数(string/cout/strlen和wstring/wcout/wsclen等)。窄字符在不同的编译器下有不同的缺省编码形式(在简体中文VC下是GB18030编码,gcc下是UTF-8编码),宽字符一般都使用unicode编码,在VC下使用UTF-16,gcc下使用UTF-32。
c++在输出窄字符时会按照程序内码原样输出,不会进行编码转换,因此在使用窄字符要求程序内码和运行环境编码一致,才不会出现乱码;
c++在输出宽字符时,会自动转换为运行环境的编码,因此只要正确设置了运行环境编码,同一个程序就可以在不同编码的运行环境下正确显示中文。在程序中设置当前环境的字符编码,通过 locale::global(locale(""))进行设置。
兼容windows和linux的字符显示的做法
对于需要支持多语种的程序,使用窄字符存储字符串常量,源程序中使用ascii字符,对于非ascii字符,如中文等通过gettext等工具放到单独的语言包中。
三、用户输入、输出以及持久化
由于用户输入、输出即从文件、网络等设施读写的数据在程序底层看来都是字节,因此存在输入时如何把字节流解释成有效的信息,在输出时怎么把程序中的信息转换为正确的字节流的问题。
程序不对内容进行处理
如果用户不需要对字节流的内容进行处理,而输入的字符编码和输出的字符编码一致,则程序不需要对数据进行任何的编码转换,只需要把读入的数据原样写到输出即可,数据的字符编码与程序的编码没有关系。
程序需要对内容进行处理
如果程序需要在一定程度上对数据进行处理(如需要判断字符个数、对字符进行比较。在字符串附加或者去掉内容),就要把数据转换为一种明确的字符编码,一般来说是程序内码,再进行处理,在处理后再转换为所需的字符编码进行输出。
1.宽字符程序
如果只需要处理采用当前运行环境字符编码的数据,可以通过ios::imbue(可以指定io流的字符编码),在输入、输出时c++标准库会自动在所指定的字符编码与程序内码之间进行编码转换。如果不使用流的话,也可以通过标准的wcstombs()或者mbstowcs()函数进行当前编码(通过locale::globale()或setlocale()指定)与宽字符之间的转换。
2.窄字符程序
对于窄字符程序,如果数据的字符编码与程序内码一致也不需要进行编码转换,直接处理即可。
四、几个小实验
case 1
在windows简体中文环境下,设置vs2013源文件的编码为utf-8(默认为gb2312,通过“文件”——“高级保存选项”,选择UTF-8),同时设置编译器编译结果的内码为UTF-8(通过在cpp和h文件的头部添加
#pragma once
#pragma execution_character_set("utf-8")
即可),然后使用如下程序:
#pragma once
#pragma execution_character_set("utf-8")
// 本文件为utf-8 编码格式
#include<iostream>
#include<string>
using namespace std;
int main(){
std::string str = "好人";
cout << str << endl;
return 0;
}
由于简体中文windows的系统环境的编码为GB18030,而源文件被设置成UTF-8编码,同时也指示编译器编译的目标文件的程序内码使用UTF-8编码,那么在输出的时候会将中文输出乱码。
case 2
在windows简体中文环境下,设置vs2013源文件为utf-8编码,而可执行文件的内码保持默认为gb2312:
//文件选择保存为utf-8格式
#include<iostream>
#include<string>
using namespace std;
int main(){
std::string str = "好人";
cout <<str << endl;
return 0;
}
编译器会按照utf-8格式解析源文件,并进行编译,编译出可执行程序的内码为gb2312,系统运行环境的编码为GBK,可以正常显示中文。
case 3
(3.0)在windows简体中文环境下,vs2013源文件分别采用gb2312和utf-8编码,可执行程序的内码分别采用gb2312和utf-8编码(四种组合),直接wcout输出宽字符,结果均为空。
#pragma once
//#pragma execution_character_set("utf-8")
// 本文件为utf-8 编码格式
#include<iostream>
#include<string>
using namespace std;
int main(){
std::wstring wstr = L"好人";
std::wcout << wstr.size() << endl; //输出为2
std::wcout << wstr << endl;
return 0;
}
(3.1)在windows简体中文环境下,vs2013源文件分别采用gb2312和utf-8编码,可执行程序的内码分别采用gb2312和utf-8编码(四种组合),imbue设置输出格式为std::locale("chs")或者通过locale::global(locale("")) 设置,然后wcout输出宽字符:
#pragma once
//#pragma execution_character_set("utf-8")
// 本文件为utf-8 编码格式
#include<iostream>
#include<string>
using namespace std;
int main(){
// locale::global(locale("")); 或者 std::wcout.imbue(std::locale("chs"));
std::wstring wstr = L"好人";
std::wcout << wstr.size() << endl;
std::wcout << wstr << endl;
return 0;
}
因为,宽字符在输出时候会自动进行编码格式的转换,对wcout指定了输出流的输出编码,则可以输出正确的结果。
case 4
在windows下使用mysqlconn库连接mysql数据库,由于为了和客户端通信,mysql数据库采用UTF-8编码。在visual studio 2013下程序访问数据库中中文字符的某条属性,在select的时候,需要将中文字符写在源代码中。由于vistual studio默认的源文件编码和可执行程序的内码都是GBK2312,因此在访问mysql数据库的时候中文字符变为乱码从而无法访问。
可以通过将包含中文字符的那个源文件(只需要含中文字符的那个即可,不需要全部)强制编译为UTF-8编码的可执行程序内码,然后访问mysql即可。
20
#pragma once
#pragma execution_character_set("utf-8")
// 本文件为utf-8 编码格式
#include<iostream>
#include<sstream>
#include"SQLExecutor.h"
using namespace std;
int main(){
SQLExecutor* sql_conn = new SQLExecutor();
std::ostringstream os;
os << "select attribute_id from attribute_define where attribute_name = '入网状态'";
std::cout << os.str() << endl;
ResultSet* rs = sql_conn->ExecuteQuery(os.str());
while (rs && rs->next()){
std::cout << "attribute_id = " << rs->getUInt(1) << endl;
}
delete rs;
delete sql_conn;
return 0;
}
原文地址:https://www.csdn.net/tags/NtTaYg0sOTgzMzctYmxvZwO0O0OO0O0O.html
c++中文编码格式的更多相关文章
- UTF-8和GBK等中文字符编码格式介绍及相互转换
我们有很多时候需要使用中文编码格式,比如gbk.gb2312等,但是因为主要针对中文编码设置,因此并不完全通用,这样一来就有了在各编码间相互转换的需求,比如和UTF8的转换.可是在我使用的过程中,却发 ...
- JAVA 编码中文简述
中文编码问题虽然是个老问题,但对不熟悉的人来说还是不好处理的.不过Java中已经有了一套比较成熟的解决方案. 首先对中文编码格式予以简单介绍:中文编码有三套国标:GB2312,GBK,GB18030, ...
- LR 解决中文乱码(来源——百度)
因为我们使用的中文操作系统默认的中文编码格式是GB2312,所以LR对服务器的返回内容自动使用GB2312方式阅读的,但是几乎所有的中文网站现在都在使用UTF-8的方式来编码,由于解码编码的方式不同最 ...
- 解决ubuntu的gedit编辑器中文乱码的问题
hello,本人 sky 又和大家见面了很多人在使用ubuntu系统时发现打开windows系统下面写的文档的话会发现乱码,是因为编码格式的问题windows系统下面是用GB2312等编码格式进行中文 ...
- 文件下载 路径中有中文 报错 提示 文件找不到 java.io.FileNotFoundException: http://192.168.1.141:8096/resources/card/comcard/????????/????????.png
此问题主要是中文编码格式不对导致的,将路径中的中文部分设置下编码就可以啦 例如: String url = "http://192.168.1.141:8096/resources/car ...
- PHP中文字符gbk编码与UTF-8编码的转换
通常PHP中上传文件,如果文件名称有中文字符,上传之后的名称是无法写入到本地的,因为上传来的编码格式一般是UTF-8的格式,这种格式是无法给文件命名并且存储到操作系统磁盘.在写入之前需要将其转换为gb ...
- Linux下文件字符编码格式检测和转换
目前多数情况下, 我们遇到的非英文字符文件都是使用UTF-8编码的, 这时一般我们查看这些文件的内容都不会有问题. 不过有时, 我们有可能会遇到非UTF-8编码的文件, 比如中文的GBK编码, 或者俄 ...
- [python IO学习篇]补充打开中文路径的文件
http://blog.csdn.net/mottolinux/article/details/525600621 关于Python编码的基本常识 在python里面 “明文”是unicode类型和s ...
- php$get中文汉字参数乱码
最近写了个简单的页面,从浏览器中传入中文参数(test.php?name=测试),不论怎么设置utf-8的页面中都显示乱码,google了一把也查到了不少解决办法,但是问题的原因到底是什么呢?没有人深 ...
- springboot同时支持访问html5和jsp时,导致后台ResponseBody返回中文乱码
背景:原系统是由springboot jsp,所有访问都是jsp 现在需要做HTML5定位,要同时支持访问HTML5和JSP 在application.yml的spring标签下配置 mvc: #vi ...
随机推荐
- MySQL 常用命令(4)------mysqladmin命令详解
mysqladmin是一个执行管理操作的客户端程序.它可以用来检查服务器的配置和当前状态.创建和删除数据库等. mysqladmin 工具的使用格式: mysqladmin [option] comm ...
- MySQL dump 备份脚本
vim db_all.sh #!/bin/sh logFile=/home/shell/db_backup.log DATE=`date +'%Y%m%d_%H_%M'` cd /home/data ...
- oracle 数据库备份脚本(数据泵1-全库)
#!/bin/sh# ################################################################### Powered by Ironfo# ## ...
- iOS 15 UI适配
1. UINavigationBar 在iOS 15中,UINavigationBar默认为透明.在滑动时会有模糊效果.如果想要一直就是模糊效果,可以通过改变scrollEdgeAppearance属 ...
- 实验:STM32-ARDUINO-ESP01采用AT指令,通过MQTT连接上ONENET
1.硬件准备 要求:STM32支持Arduino. 2.程序逻辑结构 3.主流程状态机 4.测试数据抓图 5. 关键程序代码 unsigned char g_ArrTemp[1024]; int AT ...
- Mac 卸载 Anaconda3
终端安装anaconda-clean conda install anaconda-clean 删除所有与 Anaconda 有关的文件与目录 anaconda-clean --yes 第 2 步中的 ...
- 应用Sequelize创建项目
创建项目: 第一步:安装express-generator -g 第二步:安装ejs模板 express --view=ejs 项目名 第三步:安装依赖进入项目 npm i ------------ ...
- applicationContext.xml及springMVC.xml详解
在前面的web.xml详解里,我们引入applicationContext.xml和springMVC.xml两个配置文件, 前者是spring 全局配置文件,用来控制spring 特性的, 后者则是 ...
- Leetcode——二分法bisect_left,bisect_right
!前提--列表有序 case 1 如果列表中没有元素x,那么bisect_left(ls, x)和bisec_right(ls, x)返回相同的值,该值是x在ls中"合适的插入点索引,使得数 ...
- List一边插入数据后又移除数据
记录最简单的三种方法,直接上代码: List<String> list = new ArrayList<>(); list.add("1"); list.a ...