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++中文编码格式的更多相关文章

  1. UTF-8和GBK等中文字符编码格式介绍及相互转换

    我们有很多时候需要使用中文编码格式,比如gbk.gb2312等,但是因为主要针对中文编码设置,因此并不完全通用,这样一来就有了在各编码间相互转换的需求,比如和UTF8的转换.可是在我使用的过程中,却发 ...

  2. JAVA 编码中文简述

    中文编码问题虽然是个老问题,但对不熟悉的人来说还是不好处理的.不过Java中已经有了一套比较成熟的解决方案. 首先对中文编码格式予以简单介绍:中文编码有三套国标:GB2312,GBK,GB18030, ...

  3. LR 解决中文乱码(来源——百度)

    因为我们使用的中文操作系统默认的中文编码格式是GB2312,所以LR对服务器的返回内容自动使用GB2312方式阅读的,但是几乎所有的中文网站现在都在使用UTF-8的方式来编码,由于解码编码的方式不同最 ...

  4. 解决ubuntu的gedit编辑器中文乱码的问题

    hello,本人 sky 又和大家见面了很多人在使用ubuntu系统时发现打开windows系统下面写的文档的话会发现乱码,是因为编码格式的问题windows系统下面是用GB2312等编码格式进行中文 ...

  5. 文件下载 路径中有中文 报错 提示 文件找不到 java.io.FileNotFoundException: http://192.168.1.141:8096/resources/card/comcard/????????/????????.png

    此问题主要是中文编码格式不对导致的,将路径中的中文部分设置下编码就可以啦 例如: String url =  "http://192.168.1.141:8096/resources/car ...

  6. PHP中文字符gbk编码与UTF-8编码的转换

    通常PHP中上传文件,如果文件名称有中文字符,上传之后的名称是无法写入到本地的,因为上传来的编码格式一般是UTF-8的格式,这种格式是无法给文件命名并且存储到操作系统磁盘.在写入之前需要将其转换为gb ...

  7. Linux下文件字符编码格式检测和转换

    目前多数情况下, 我们遇到的非英文字符文件都是使用UTF-8编码的, 这时一般我们查看这些文件的内容都不会有问题. 不过有时, 我们有可能会遇到非UTF-8编码的文件, 比如中文的GBK编码, 或者俄 ...

  8. [python IO学习篇]补充打开中文路径的文件

    http://blog.csdn.net/mottolinux/article/details/525600621 关于Python编码的基本常识 在python里面 “明文”是unicode类型和s ...

  9. php$get中文汉字参数乱码

    最近写了个简单的页面,从浏览器中传入中文参数(test.php?name=测试),不论怎么设置utf-8的页面中都显示乱码,google了一把也查到了不少解决办法,但是问题的原因到底是什么呢?没有人深 ...

  10. springboot同时支持访问html5和jsp时,导致后台ResponseBody返回中文乱码

    背景:原系统是由springboot jsp,所有访问都是jsp 现在需要做HTML5定位,要同时支持访问HTML5和JSP 在application.yml的spring标签下配置 mvc: #vi ...

随机推荐

  1. JS数组的交集与差集

    有两个数组arr1,arr2 实现arr2中去除arr1相同的元素 e.g arr1=[1,2,3] arr2=[2,3,4] ===> result = [4] 实现 获取两个数组(arr1, ...

  2. pytorch学习笔记(4)--dataloader

    batch_size:有多少张 shuffle=True:顺序不打乱 num_workers: 进程数 drop_last:最后不够64张是否舍去 import torchvision from to ...

  3. Spring boot jar包解压后重新压缩命令

    进入解压的目录/demo,运行 jar cvfM0 demo.jar * 压缩后的项目即可运行 参考:https://www.cnblogs.com/liyanbin/p/6088458.html

  4. Windows D3D渲染到纹理

    D3D渲染到纹理 1 #include <d3dx9.h> 2 3 //---------------------------------------------------------- ...

  5. Mysql修改字段类型修改

    Mysql修改字段类型与长度修改等 alter table news modify column title varchar(130); alter table 表名 modify column 字段 ...

  6. 杭电OJ--1003题C++实现

    #include<iostream>using namespace std;int a[100000];void solve(int k,int n,int t);int main(){  ...

  7. Python循环任务,错误打包输出

    有时候,多个任务循环在跑,但不想中间任何一个错误,停止主线程,但又想在主线程运行结束后,采集运行过程中所有的错误信息. 这种刁钻的想法,我自问自答,记录一下操作方法. err_list = [] ma ...

  8. vue移动端在线签名

    <template> <section class="signature"> <div class="signatureBox"& ...

  9. 延期!欧盟新标EN IEC 62368-1:2020延至2024年7月6日生效

    近日,TC108X成员投票同意将EN IEC 62368-1:2020(对应IEC 62368-1第三版)的DOW (Date Of Withdrawn)日期由原先的2023年1月6日延长至2024年 ...

  10. 4组-Beta冲刺-3/5

    一.基本情况 队名:摸鲨鱼小队 组长博客:https://www.cnblogs.com/smallgrape/p/15600609.html github链接:https://github.com/ ...