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即可。

#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;
}

c++程序编码的更多相关文章

  1. [转]JavaScript程序编码规范

    原文:http://javascript.crockford.com/code.html 作者:Douglas Crockford 译文:http://www.yeeyan.com/articles/ ...

  2. 程序编码(机器级代码+汇编代码+C代码+反汇编)

    [-1]相关声明 本文总结于csapp: 了解详情,或有兴趣,建议看原版书籍: [0]程序编码 GCC调用了一系列程序,将源代码转化成可执行代码的流程如下: (1)C预处理器扩展源代码,插入所有用#i ...

  3. JavaEE程序编码规范

    JavaEE程序编码规范 目   录 JAVA程序编码规范1 1变量的命名规则1 1.1常量(包含静态的)1 1.2类变量(静态变量)及实例变量1 1.3局部变量1 1.4参数2 1.5其它2 2方法 ...

  4. qt creator修改程序编码(解决中文乱码问题)的方法

    qt creator修改程序编码(解决中文乱码问题)的方法 qt creator修改程序编码的功能有几处. 1.edit - select encoding 选择载入(显示)编码和储存编码,其中GB2 ...

  5. 提高你的C#程序编码质量

    摘自陆敏技之<编写高质量代码:改善C#程序的157个建议>,编写C#程序代码时应考虑代码效率.安全和美观,可参考下述建议.想成为一名合格的搬砖工,牢记吧!! 基本语言要素 1.正确操作字符 ...

  6. ruby 程序中的文字编码

    1,问题 在写一个统计代码行数的脚本时遇到一个问题: 代码: file_name = "code.rb"c = 0File.foreach(file_name) do |x| ne ...

  7. 应用程序框架实战三十四:数据传输对象(DTO)介绍及各类型实体比较

    本文将介绍DDD分层架构中广泛使用的数据传输对象Dto,并且与领域实体Entity,查询实体QueryObject,视图实体ViewModel等几种实体进行比较. 领域实体为何不能一统江湖? 当你阅读 ...

  8. 将程序部署到weblogic出现乱码问题

    出现错误: 将文件部署到weblogic上,在linux环境下运行程序时出现乱码问题 原因: (1)可能是linux系统的编码问题 解决办法:登陆weblogic 输入命令: cd /etc/sysc ...

  9. Linux Linux程序练习十二(select实现QQ群聊)

    //头文件--helper.h #ifndef _vzhang #define _vzhang #ifdef __cplusplus extern "C" { #endif #de ...

随机推荐

  1. sys模块的初步认识

    #!/usr/bin/python # Filename: cat.py import sys def readfile(filename): '''Print a file to the stand ...

  2. js查找出现次数最多的字母

    <!doctype html><html><head><meta charset="utf-8"><title>无标题文 ...

  3. hbase centOS生产环境配置笔记 (1 NameNode, 1 ResourceManager, 3 DataNode)

    本次是第一次在生产环境部署HBase,本文若有配置上的不妥之处还请高手指正. hadoop版本:hadoop-2.4.1 HBase版本:hbase-0.98.6.1-hadoop2 Zookeepe ...

  4. 2016年12月13日 星期二 --出埃及记 Exodus 21:8

    2016年12月13日 星期二 --出埃及记 Exodus 21:8 If she does not please the master who has selected her for himsel ...

  5. js动画 无缝轮播 进度条 文字页面展示 div弹窗遮罩效果

    1.无缝轮播 <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.a ...

  6. .Net六大验证及使用方法

    C#包含有六种验证方式,分别为: 一.非空验证  RequiredFieldValidator. 二.对比验证 CompareValidator. 三.范围验证 RangeValidator. 四.正 ...

  7. 64位Linux安装android开发IDE的全过程

    首先特别感谢这个链接: http://www.androiddevtools.cn/ 提供了几乎所有的安卓开发需要用到的资源. 操作系统:CentOS 7. 一.android studio 这个折腾 ...

  8. GBrowse配置相关资料

    GBrowse配置相关资料(形状.颜色.配置.gff3) http://gmod.org/wiki/Glyphs_and_Glyph_Optionshttp://gmod.org/wiki/GBrow ...

  9. Java EE 在网页输出九九乘法表、三角形、菱形

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  10. eclupse启动报 Failed to load JavaHL Library.错

    解决办法: window --> preferences --> Team --> SVN --> Client选项选择: SVNKit x.x.x.xxx