• 长期以来,很多人都清楚,一旦C++源码中直接使用了中文,这样的源码想要跨平台(I18N)会非常困难。

随着:

  • Windows下:MSVC2010成为主流
  • Linux下:GCC升级到4.6

C++中的中文问题 才算有了一个比较优雅的、跨平台的Workaround。

(本文讨论编译器范围:GCC4.6+, MSVC2010sp1+ 。本文属于QString系列,但暂不涉及QString)

C++ 中文问题

要在C++中正确使用中文,必须要了解下面两个概念:

源码字符集(the source character set)

源码文件是使用何种编码保存的

执行字符集(the execution character set)

可执行程序内保存的是何种编码(程序执行时内存中字符串编码)

C++98的问题: 既没有规定源码字符集,也没有规定执行字符集

这个... 如何理解?不妨看个例子

例子

这个要求高么?

  • 一个简单的C++程序,只是希望它能在简体中文Windows、正体中文Windows、英文版Windows、Linux、MAC OS...下的结果一致。
//main.cpp
int main()
{
char mystr[] = "老老实实的学问,来不得半点马虎";
return sizeof mystr;
}

可以试着反问自己两个问题

  • 这个源码文件是何种编码保存的?(有确定答案么?)
  • mystr中是什么内容?(有确定答案么?)

对C++来说,这两个都不确定。

  • 固定平台的话,还能忍忍
  • 要跨平台的话,这种东西...

GCC

在GCC下,这两个都可以使用你自己喜好的编码(如果不指定,默认都是UTF8)

-finput-charset=charset
-fexec-charset=charset

除了前两个选项外,还有一个:

-fwide-exec-charset=charset

wide? 不妨先猜一下它是干嘛的

MSVC

MSVC没有类似前面的选项。

源码字符集如何解决?

有BOM么,有则按BOM解释,无则使用本地Locale字符集(随系统设置而变)

执行字符集如何解决?

使用本地Locale字符集(随系统设置而变)

挺霸道哈(当然,源码中可以使用#pragma setlocale("..."),但功能很有限,比如Windows没有utf8的locale,所以...)。

另外,和GCC对应的wide-exec-charset呢?

宽执行字符集如何解决?

不妨先考虑一下

怎么办?

这才两个编译器,看起来就这么复杂了。而C++编译器的数目远大于2.

要想跨平台,必须确保这两个字符集都是“确定”的,而能胜任该任务的字符集,似乎理想的也只能是...

UTF-8方案

  • 如果我们将源码保存成utf8,执行字符集也选为utf8,那么天下将太平了。使用非ASCII字符的源码文件也就可以在不同国家的用户间无障碍流通了 ;-).

源码保存成UTF-8没有什么困难,但是,执行字符集需要是UTF-8。没那么简单

对GCC来说,这个问题很简单(默认的编码选项足够了):

  • 只要源码文件保存成utf8即可(带或不带BOM均可)
  • 早期的gcc不接收带BOM的utf8源码文件,现在,至少在GCC4.6中,这一限制不再存在。

对MSVC来说,这个问题异常复杂:

  • 对MSVC2003来说,只要源码保存成不带BOM的utf8即可
  • 对MSVC2005、(没在SP1基础上装热补丁的)MSVC2008来说。完全没办法
  • 直到MSVC2010sp1,才算提供了一个解决方案。源码保存成带BOM的utf8,utf16,...,然后添加
#pragma execution_character_set("utf-8")

要想跨GCC4.6+和MSVC2010sp1+,我们需要取它们的交集:也就是

  • 源码保存成带BOM的utf8
  • 为MSVC添加#pragma

//main.cpp

#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif int main()
{
char mystr[] = "老老实实的学问,来不得半点马虎";
return sizeof mystr;
}

C++11

等到MSVC支持C++11的String Literals之时,我们就没必要用那个蹩脚的pragma了,直接

    char mystr[] = u8"老老实实的学问,来不得半点马虎";

即可(尽管现在在GCC下没问题,但要跨平台,估计要等到Visual C++ 12了)。

有个问题?

C++98中不是有个wchar_t么,它不是用来表示unicode字符的么?

Unicode 4.0标准的5.2节是如何说的:

The width of wchar_t is compiler-specific and can be as small as 8 bits. Consequently, programs that need to be portable across any C or C++ compilershould not use wchar_t for storing Unicode text. The wchar_t type is intended forstoring compiler-defined wide characters, which may be Unicode characters in some compilers.

在回头看看GCC的选项

-fwide-exec-charset=charset

尽管GCC为其提供的默认编码是UTF16或UTF32(取决于wchar_t的宽度),但该编码是可以随意设置的。

尽管这个东西不保证跨平台,也很不好玩, 但是,由于在windows下面wchar_t用来表示utf16字符,而且直接对应系统API接口,所以在类型char16_t普及之前,还是很重要的。

C++11执行字符集

前面提到的u8就是C++11为“执行字符集”所做的努力之一。

新明确规定了utf8、utf16和utf32这3种执行字符集。

char*

u8"中文"

char16_t*

u"中文"

char32_t*

U"中文"

可是C++11并没有规定源码字符集

const char* mystr=u8"中文";

C++标准对编译器说,我不管这个文件的具体编码是什么,但你必须给我生成对应utf8编码的字节流。

编译器似乎有点傻了吧?不知道源文件的编码,我如何转换

于是:

MSVC说:源码文件必须有BOM,不然我就认为你是本地locale的编码

GCC说:我认为你就是utf8编码,除非通过命令行通知我其他编码

在C++11标准下,对源码编码 简单的处理办法还是,使用带BOM的UTF8保存。

参考

QString乱谈(2)的更多相关文章

  1. QString 乱谈(1)

    一个月前尝试写了一篇关于QStringLiteral,存盘时MoinMoin罢工了.吸取一点经验,还是写成短篇吧 可是,可是,QString不就是简简单单一个字符串么?能有什么可谈的.真的么... ( ...

  2. [转载]QString 乱谈(3)-Qt5与中文

    原文地址http://blog.csdn.net/dbzhang800/article/details/7542672?reload 两个月前,简单写过QTextCodec中的setCodecForT ...

  3. QString 乱谈(3)-Qt5与中文

    原文请看:http://blog.csdn.net/dbzhang800/article/details/7542672 两个月前,简单写过QTextCodec中的setCodecForTr等终于消失 ...

  4. 微软ASP.NET技术“乱谈”

    微软ASP.NET技术“乱谈” 2014新年了,顺手写的一点文字,主要谈谈我对当前微软ASP.NET技术的看法,比较随意,大伙儿随便看看吧. 1 当前微软Web平台技术全貌 从2002年发布.NET ...

  5. C++矢量图形库系列(1)——矢量图形库乱谈(转)

    转自:http://blog.sina.com.cn/s/blog_4265e1760100lg03.html 本系列篇章的主要内容是讲解矢量图形库的编译.开发和使用.并不对他们周边的内容做过多的描述 ...

  6. 优测优社区干货精选|老司机乱谈编辑器之神——vim

    文 / 腾讯 吴双 前言 优测小优 有话说: 腾讯优测只有应用测试大神?不不不,我们还有各种研发大牛! *** vim 是一种信仰,我自从2004年有了这个信仰,已经12个年头了.本文介绍了学习vim ...

  7. [转]vnpy乱乱谈 02架构

    vnpy乱乱谈 02架构 转自:http://101.132.65.227/?p=51 听到架构这个词先不要害怕. 其实这部分内容还是挺简单的. 一般而言, 一个交易系统我们可以简单的分成输入, (系 ...

  8. JIT-动态编译与AOT-静态编译:java/ java/ JavaScript/Dart乱谈

    C 和 C++ 之类的编译语言性能远超Java,但是生成的代码只能在有限的几种系统上执行,这就有了Java的存在基础(JVM-跨平台) 早期 Java 运行时所提供的性能级别远低于 C 和 C++ 之 ...

  9. 乱谈Qt事件循环嵌套

    本文旨在说明:QDialog::exec().QMenu::exec()等开启的局部事件循环,易用的背后,还有很多的陷阱... 引子 Qt 是事件驱动的,基本上,每一个Qt程序我们都会通过QCoreA ...

随机推荐

  1. iOS_Quartz 2D绘图

    目  录: 一.基础知识掌握 二.Quartz 2D绘图基础:CGContextRef实现简单地绘制图形 三.CGContextRef实现文字.图片.基于路径的图形绘制 四.在内存中绘制位图 五.添加 ...

  2. RDLC 微软报表 导出Excel时产生多个工作表 (worksheet)

    . I have added two obejcts data source to Report Viewer. 2. in RDLC i have created two tables and in ...

  3. 自动生成Mapper代码

    public class BeanMapperTest { @Test public void build() throws Exception { Class clazz = RiskAccess. ...

  4. CentOs linux安装SVN服务

    SVN服务器有2种运行方式:1.独立服务器(例如:svn://xxx.com/xxx):2.借助apache   (例如:http://svn.xxx.com/xxx):为了不依赖apache,我选择 ...

  5. Excel下载打不开

    1.问题描述:今天遇到个问题,对于定时发送邮件,前两天还正常,今天发现邮件能收到,但打不开,显示如下错误: 预览邮件显示: 点击Excel打开,显示如下: 2.问题解决方案 删除对于服务器上部分空间内 ...

  6. 什么是OOM?如何解决OOM问题!

    1.什么是OOM? 程序申请内存过大,虚拟机无法满足我们,然后自杀了.这个现象通常出现在大图片的APP开发,或者需要用到很多图片的时候.通俗来讲就是我们的APP需要申请一块内存来存放图片的时候,系统认 ...

  7. 剑指Offer——重建二叉树2

    Question 输入某二叉树的后序遍历和中序遍历的结果,请重建出该二叉树.假设输入的后序遍历和中序遍历的结果中都不含重复的数字.例如输入后序遍历序列{1, 3, 4, 2}和中序遍历序列{1, 2, ...

  8. hadoop 输出中文乱码问题

    本文转载至: http://www.aboutyun.com/thread-7358-1-1.html hadoop涉及输出文本的默认输出编码统一用没有BOM的UTF-8的形式,但是对于中文的输出wi ...

  9. 解决可以Ping通ip地址,但Ping不通域名的思路

    在正常的网络故障处理中,ping命令是大家经常用到的,出现ping通ip地址,但ping域名是出现超时情况,一般是由于TCP/IP协议中的“DNS设置”不正确,请检查其中的配置,或者更换其他可用的DN ...

  10. java 发送http 的get|post 请求

    <div>  package wzh.Http; import java.io.BufferedReader; import java.io.IOException; import jav ...