【转载】MSVC中C++ UTF8中文编码处理探究
字符集
先说一个名词:字符集,没听过的先百度一下,其实就是一种将字符编码的格式,像我们常说的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中文编码处理探究的更多相关文章
- MSVC中C++ UTF8中文编码处理探究
字符编码的问题,上大学那会儿就遇到过,一直都是云里雾里,没太搞清楚.最近又遇到了问题,想在C++的控制台上输出Utf-8编码的汉字字节流.尝试了好多次都是乱码,后来花了些时间查查资料,又和同事交流了一 ...
- [转载]eclipse中设置文件的编码格式为utf-8
免责声明: 本文转自网络文章,转载此文章仅为个人收藏,分享知识,如有侵权,请联系博主进行删除. 原文作者:ryxxlong 原文地址:http://ryxxlong.iteye ...
- 记住,永远不要在MySQL中使用“utf8”编码[转载]
记住,永远不要在MySQL中使用“utf8”编码 原创: 无明.Adam 聊聊架构 6月15日 最近工作中我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一 ...
- 【转载】在Windows终端中显示UTF-8字符
一直苦恼于如何在Windows终端中显示UTF-8字符的问题.比如,在MySQL命令行下,如果数据库的编码是UTF-8,那么,在查询数据库的时候,里面的中文都会变成乱码.今天半无意的搜索了一下,结果发 ...
- 在msvc中使用Boost.Spirit.X3
Preface “Examples of designs that meet most of the criteria for "goodness" (easy to unders ...
- Pycharm中不支持中文编码的解决方案。Pycharm中文报错。 Pycharm出现的部分快捷键无效及解决办法
Pycharm中不支持中文编码的解决方案.Pycharm中文报错. 1. 打开Pycharm ----> File ----> Default setting ------> Ed ...
- PHP+MySQL中对UTF-8,UTF8(utf8),set names gbk 的理解
问题一:在我们进行数据库操作时会发现,数据库中表的编码用的是utf-8,但是在进行dos命令是要使用set names gbk (一)Mysql中默认字符集设置有四级:服务器级,数据库级,表级,和字段 ...
- 为 Apache 配置 UTF-8 中文编码
为 Apache 配置 UTF-8 中文编码 cat /etc/httpd/conf/httpd.conf | grep -n utf -C2 30-# 31-ServerRoot "/et ...
- SQL学习笔记之MySQL中真假“utf8” 问题
0x00 MySQL中UTF8报错 最近我遇到了一个 bug,我试着通过 Rails 在以“utf8”编码的 MariaDB 中保存一个 UTF-8 字符串,然后出现了一个离奇的错误: Incorre ...
- 如何快速转载CSDN中的博客
看到一篇<如何快速转载CSDN中的博客>,介绍通过检查元素→复制html来实现快速转载博客的方法.不过,不知道是我没有领会其精神还是其他原因,测试结果为失败.
随机推荐
- https代理服务器(四)java动态签发【失败】
https://zhuanlan.zhihu.com/p/355241710?utm_id=0 http://t.zoukankan.com/xiaxj-p-8961131.html https:// ...
- 使用HttpClient4.5 使用MultipartEntityBuilder 类发送 multipart/formdata 格式给第三方接口 失败的原因
1.使用MultipartEntityBuilder的setCharset方法设置 utf-8格式2.在httppost 请求头上 加上Content-Type", "multip ...
- RestTemplate 连接池最大链接数
原文链接:https://www.cnblogs.com/x-x-736880382/p/11591906.html 以前我们项目都是基于Apache HttpClient 连接池进行web 接口调用 ...
- redis常用命令之Hash
redis常用命令之Hash Hash常用命令 redis 可以理解为一个全局的大字典,key就是数据的唯一标识符.对应的key不同,value也不同.redis有5个基本的数据类型. 1 redis ...
- 信息安全day1
课程目标:中小型网络建立.操作和故障排除,连接到WAN和实施网络安全 路由器三层协议功能 多层交换机具备三层协议的功能 终端服务器:特殊的路由器 网云:1.未知网络区域 2.不受自己管理的网络区域 A ...
- [BOM]实现页面loading效果,在图片资源加载完之前显示loading
使用到jquery. 判断整个页面是否加载完: // 这是根据js判断,页面加载完毕就显示 window.onload = function () { // console.log('load com ...
- stm32的boot0和boot1
stm32的boot0和boot1 TM32三种启动模式对应的存储介质均是芯片内置的,它们是: 1)用户闪存 = 芯片内置的Flash.2)SRAM = 芯片内置的RAM区,就是内存啦.3)系统存储器 ...
- javaScript面向对象(继承篇)
一.构造函数继承 function Parent() { this.money = '2亿' this.eat = function () { console.log('吃饭') } } func ...
- jadx 定位方法
目录 链接参数定位 链接参数定位 通过搜索请求链接中的参数来定位函数位置,如下图所示,请求链接为 https://www.python-spider.com/api/app1,app1为链接标识,可以 ...
- Ubuntu 20.04 部署Prmoetheus+grafana+mysql+mysqld_exporter+node_exporter
Prometheus简介 Prometheus是一个功能强大的开源监控系统,可从您的服务中收集指标并将其存储在时间序列数据库中.它通过Grafana等工具提供多维数据模型,灵活的查询语言和多样化的可视 ...