字符集


  先说一个名词:字符集,没听过的先百度一下,其实就是一种将字符编码的格式,像我们常说的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. highcharts冷门功能总结

    1.散点图控制点的样式. Highcharts.chart('container', { series: [{ type: "scatter", marker: { fillCol ...

  2. hover状态下改变图片颜色的方式 悬停图片切换;css变量;悬停svg图片改变颜色;VUE

    由外部json文件,按照配置方式引入图片路径时,需要一些值得注意的语法来动态引入和改变图片 1.图片路径设置 ,按照img标签动态引入图片 <img src=''/> 路径不引入变量,此时 ...

  3. elasticSearch(六)--全文搜索

    数据案例 1.匹配查询 a.单词查询 执行match步骤: ·检查field类型:title字段为(analyzed)字符串,所以搜索时,title需要被分析. ·分析查询字符串:QUICK! 经过标 ...

  4. 淘淘商城项目技术点-7:Nginx

    Nginx--Ngine X,是一款自由的.开源的.高性能HTTP服务器和反向代理服务器:也是一个IMAP.POP3.SMTP代理服务器:也就是说Nginx本身就可以托管网站(类似于Tomcat一样) ...

  5. ping Hyper-V内虚拟机网络延迟

  6. vs2010 项目属性窗口

    配置一些项目编译输出的类型(比如是编库还是编demo).编译输出结果的名字.编译输出结果的路径等等 Configuration Properties->General 配置在编译工程所需要的头文 ...

  7. Windows 操作

    一.基础命令 1. 盘符切换:D:: 2. 查看当前目录文件:dir: 3. 当前盘符内目录切换:cd path: 二.其他命令 1. netstat:查看网络端口状态 A. 查看某一端口信息:net ...

  8. Ubuntu 20.04 部署kubernetes 网络组件calico-v3.2.1

    1.官方网址: https://projectcalico.docs.tigera.io/archive/v3.21/getting-started/kubernetes/self-managed-o ...

  9. 计算机网络基础(3):IP与子网掩码/ ping/ ipconfig/ VLAN/ 网络服务器配置

    chapter4 构建中型网络 1. IP地址与子网掩码 A类地址:网络ID开头是0,范围从00000001到01111110,126个,其中0 127留作他用.在每个网段里(网络ID),可以容纳2* ...

  10. dota中的哲理

    战术和战略: 6k分和3k分玩家的最重要的区别不是英雄玩的不好,而是整体战略不明确. dota玩家游戏时长超过1000h的比比皆是,这些玩家里面分数差距相当大.高的7k往上,低的2k深坑爬不出来. 这 ...