字符集


  先说一个名词:字符集,没听过的先百度一下,其实就是一种将字符编码的格式,像我们常说的ASCII,UTF8,GBK都是常用的字符集。

  首先要清楚,从你在编辑器里输入一个UTF8汉字开始,到最终在控制台上显示出来,整个流程涉及到三个概念,分别是源码字符集,执行字符集,解析字符集。

  分别解释一下:

  源码字符集:就是你的源代码文本文件的字符集,如果你手头有NodePad++这样类似的文本编辑器你可以打开看一下你的字符集,或者用Windows记事本另存为的时候也会显示文本格式。要知道,你的源代码文本文件是以二进制的形式躺在硬盘里的,无论中文英文都一样,当你输入一个汉字后保存关闭,这个汉字就是按照你指定的字符集转换成二进制编码保存下去的,当你在以这个格式打开文件时候,就再按照你指定的字符集把二进制转回来。如果两次使用不同的字符集,也就会出现乱码了。

  执行字符集:在C++里 char* str= “我”;执行字符集决定了这行代码在编译器进行编译的时候str存储的字节到底是什么,你可能会说源码字符集不是已经决定了这个”我”的二进制表示了么,没错,但是这个执行字符集就是让你在这里对它再解释一次。比如我源码字符集可能是UTF8的,但是我可以通过执行字符集来让最终ptr存储的是GBK的字节编码。

  解析字符集:最终要还原显示这些二进制字节编码的时候,就需要用到它。比如通过printf把前面的str显示到控制台时,这个printf就会按照解析字符集来解析这些字节编码,找到指定字符显示出来。

  饶了一圈,好像也不是很乱,但是这里面是有很多坑的。这几个字符集的处理都是跟具体编译器甚至操作系统相关的,不同的编译器是有差别的,我这里只说Windows7系统下VS2013(msvc编译器)的环境。

VS2013中的字符集概念


1.对于源码字符集在VS2013文件->高级保存选项->编码中可以查看设置当前源代码文件的源码字符集。

2.对于执行字符集,VS2013默认根据系统的Locale来决定执行字符集,一般大家都是windows中文系统,Locale是中国,那么就是GBK编码。

3.对于解析字符集,我试了一下,如果没有手动更改的话VS2013的标准输入输出(printf)到命令行也是根据系统Locael决定的,也就是GBK。

案例分析


  现在我们就分析一下,假如下面这段源码我们用UTF8格式保存(无Bom).分析一下控制台上显示的结果。

char* str= “我”;
printf(“%s\n”,str);

1.首先这个代码文件的文本中”我”这个汉字是以E68891三个字节编码的.

2.当编译器编译这段代码时,执行字符集默认是GBK,那么编译器要决定str的字节内容,就要把文本里保存的字节内容转为GBK,这里就有个值得注意的问题,既然要转换到GBK,就需要知道从什么格式转换到GBK,MSVC怎么知道源格式呢?方法只有一个就是分析你的源文件有没有有BOM,要是有就按照BOM它就认为原格式就是BOM指定的格式(不了解BOM可以先百度一下),如果没有BOM他就认为你的源码字符集是Locale关联的。刚才说了我们是用UTF8无BOM格式保存的源文件,所以编译器认为源码文本中的”我”是GBK编码保存的。

3.那从GBK到GBK,MSVC不会进行任何转换,这里有个小问题,提醒一下,这个代码应该是编译不通过的,因为GBK中汉字是2个字节表示的,而UTF8中是三个字节,所以编译器为了凑数会把”我”字后面的双引号给吃掉,转成了两个GBK汉字编码E688,9122(22是引号的UTF8编码),没有引号编译器就会报错,最简单的解决办法就是在在后面在加一个汉字变成偶数个就没问题了。

4.程序运行起来后printf输出到控制台,这时候用到的解析字符集也是GBK的,就会用内存里的E688,9122去GBK字符集里找到对应编码的汉字“鎴?”。这当然就错了。

解决方案 


这就是我一开始出现的错误,既然知道问题了,那怎么改呢,为了让UTF8编码的源文件中的”我”字可以显示到命令行上,我们需要进行如下分析:

1.首先一定要在编译的时候让str的字节内容是UTF8格式的才行,那就需要让执行字符集是UTF8才行,前面说到MSVC执行字符集是根据Locale来决定的,本来是没法更改的,但是微软后来打了个小不定添加了一个预处理#pragma execution_character_set("utf-8")。来告诉编译器执行字符集设置为UTF8。

2.编译时候进行转换到执行字符集需要知道源码字符集,之前我们是没有带BOM,这导致MSVC认为我们的源文件是GBK编码的,但其实我们是UTF8编码,这就需要我们保存源码的时候改为用UTF8带BOM的格式。这样就不会有问题了。

3.最后要显示出来,既然内存里是UTF8编码,解析肯定也要按UTF8格式来解析,所以我们要把默认的解析字符集从GBK设为UTF8,最简单的方法就是在输出之前调用system(“chcp 65001”);这是命令行设置当前代码页的命令。

  这样应该就能正常显示UTF8字符了,不过有个问题就是如果str用cout输出的话,依然是乱码,这个可能是因为cout有自己的解析字符集,不会随着chcp命令改变。这个有待研究,哪位同学知道,可以留言告诉我。再说一点#pragma execution_character_set("utf-8")这个预处理在C++11里已经不再需要了,C++11可以指定字符串字面量的执行字符集了,u8”我”。就这么简单。但是vs2013并不支持这个功能。这篇文章讲述的内容,并不在于如何把一个UTF8格式的C++字面量输出到控制台。而是在于通过这个例子来了解MSVC C++是如何处理UTF8中文字符的。

原文地址http://www.cnblogs.com/Esfog/p/MSVC_UTF8_CHARSET_HANDLE.html

终极解决方案


1、.cpp源码保存为UTF-8 BOM格式,VS2013文件->高级保存选项->编码->Unicode(UTF-8 带签名) - 代码页 65001;

2、cpp源代码前加入编译选项:

#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif

【转载】MSVC中C++ UTF8中文编码处理探究的更多相关文章

  1. MSVC中C++ UTF8中文编码处理探究

    字符编码的问题,上大学那会儿就遇到过,一直都是云里雾里,没太搞清楚.最近又遇到了问题,想在C++的控制台上输出Utf-8编码的汉字字节流.尝试了好多次都是乱码,后来花了些时间查查资料,又和同事交流了一 ...

  2. [转载]eclipse中设置文件的编码格式为utf-8

    免责声明:     本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除.     原文作者:ryxxlong     原文地址:http://ryxxlong.iteye ...

  3. 记住,永远不要在MySQL中使用“utf8”编码[转载]

    记住,永远不要在MySQL中使用“utf8”编码 原创: 无明.Adam 聊聊架构 6月15日 最近工作中我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一 ...

  4. 【转载】在Windows终端中显示UTF-8字符

    一直苦恼于如何在Windows终端中显示UTF-8字符的问题.比如,在MySQL命令行下,如果数据库的编码是UTF-8,那么,在查询数据库的时候,里面的中文都会变成乱码.今天半无意的搜索了一下,结果发 ...

  5. 在msvc中使用Boost.Spirit.X3

    Preface “Examples of designs that meet most of the criteria for "goodness" (easy to unders ...

  6. Pycharm中不支持中文编码的解决方案。Pycharm中文报错。 Pycharm出现的部分快捷键无效及解决办法

    Pycharm中不支持中文编码的解决方案.Pycharm中文报错. 1. 打开Pycharm ---->  File ----> Default setting ------> Ed ...

  7. PHP+MySQL中对UTF-8,UTF8(utf8),set names gbk 的理解

    问题一:在我们进行数据库操作时会发现,数据库中表的编码用的是utf-8,但是在进行dos命令是要使用set names gbk (一)Mysql中默认字符集设置有四级:服务器级,数据库级,表级,和字段 ...

  8. 为 Apache 配置 UTF-8 中文编码

    为 Apache 配置 UTF-8 中文编码 cat /etc/httpd/conf/httpd.conf | grep -n utf -C2 30-# 31-ServerRoot "/et ...

  9. SQL学习笔记之MySQL中真假“utf8” 问题

    0x00 MySQL中UTF8报错 最近我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一个 UTF-8 字符串,然后出现了一个离奇的错误: Incorre ...

  10. 如何快速转载CSDN中的博客

    看到一篇<如何快速转载CSDN中的博客>,介绍通过检查元素→复制html来实现快速转载博客的方法.不过,不知道是我没有领会其精神还是其他原因,测试结果为失败.

随机推荐

  1. A表某字段==B表某字段 更新A表的数据

    update mls_supplytask t1 -- 供应商认证任务 JOIN mls_sup_cert_report t2 -- 供应商认证报告 on t1.id = t2.certTaskId ...

  2. python手动安装包办法

    首先去官网找知己需要的包,我这是以自己安装为例 先找需要安装的包然后看箭头准备下载 我这里选择的是tar压缩格式的点一下箭头指的地方会弹出下载按钮,之后下载即可 找到自己安装的python文件所在的位 ...

  3. nginx: the "ssl" parameter requires ngx_http_ssl_module in /usr/local/nginx/conf/nginx.conf

    Nginx如果未开启SSL模块,配置Https时将提示如题错误 原因:nginx缺少http_ssl_module模块,编译安装的时候带上--with-http_ssl_module配置就行了,但是现 ...

  4. C++future promise

    A future is an object that can retrieve a value from some provider object or function, properly sync ...

  5. C# goto 语法

    test: Console.WriteLine("yest"); goto test;

  6. C语言-猜数游戏

    整理文件发现以前写的C语言猜数游戏 1-效果演示 2-程序 #include <stdio.h> #include <stdlib.h> #include <time.h ...

  7. Java-面向对象进阶 方法继承、重写

    1.继承 子类继承父类后自动拥有父类非私有的属性和方法 Java中,一个父类可以被多个子类继承,一个子类只能继承一个父类 除了继承父类的属性和方法外,子类还拥有自己特有的属性和方法 如果子类的方法与父 ...

  8. PyMySQL删除

    title: PyMySQL删除 author: 杨晓东 permalink: PyMySQL删除 date: 2021-10-02 11:27:04 categories: - 投篮 tags: - ...

  9. JS中有关闭包的相关内容及介绍

    1 var obj = (function (arg) { 2 // 这里就是一个简单的闭包,将局部变量 test和函数fn1 return出去 3 // 这样obj就可以拿到函数内部定义的变量在函数 ...

  10. 利用python中的win32com模块操作Word、Excel文件

    word操作 doc文件转换为docx文件 安装win32com模块:pip3 install pypiwin32 import os from win32com.client import Disp ...