专栏首页祥的专栏[Qt]中文乱码问题-1

[Qt]中文乱码问题-1

原创文章

原文链接:https://blog.csdn.net/humanking7/article/details/81292013


  • C++ 中文问题
  • 例子
  • GCC
  • MSVC
  • 怎么办?
  • UTF-8方案
  • C++11
  • 有个问题?
  • C++11执行字符集
  • 我的理解和总结
  • 参考文章

转载文章,对于文章稍加编辑,文后有原文链接。


长期以来,很多人都清楚,一旦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没有utf8locale,所以…)。

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

问题

解释

宽执行字符集如何解决?

不妨先考虑一下

怎么办?

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

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

UTF-8方案

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

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

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

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

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

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

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

  • 源码保存成带BOMutf-8
  • 为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++11String 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为其提供的默认编码是UTF16UTF32(取决于wchar_t的宽度),但该编码是可以随意设置的。

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

C++11执行字符集

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

新明确规定了utf8utf16utf32这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保存。

我的理解和总结

我一般的开发环境为 WIn7 64bit + VS2013 + Qt5.5。 一般VS2013默认保存源文件的编码格式为GB2312,所以对于Qt的中文显示问题,屡试不爽的方法就是,在文件中加入:

#pragma execution_character_set("utf-8")

但是,用Git进行版本控制的时候,就可以看到注释中的乱码。所以最好的方法还是将源文件转换为UTF-8的格式,至于加不加BOM,打算在下一篇博文进行探究。

参考文章

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Java并发之CountDownLatch(等待多个并发事件的完成)引入CountDownLatch类CountDownLatch类的具体实例CountDownLatch小结

    Java在JDK1.5之后引入了CountDownLatch类。这个类是一个同步辅助类。用于一个线程等待多个操作完成之后再执行,也就是这个当前线程会一直阻塞,直...

    desperate633
  • 【Python3】02、python编码

           因为字符编码的问题而苦恼不已,于是阅读了大量的博客,再进行了一定的测试,基本搞清楚了编码问题的前因后果。

    py3study
  • UNICODE与ASCII

         ASCII 是用来表示英文字符的一种编码规范。每个ASCII字符占用1 个字节,因此,ASCII 编码可以表示的最大字符数是255(00H—FFH)。...

    lulianqi
  • Python入门之字符编码

    一、字节编码的基础知识 一、计算机基础知识 #1 我们的程序都是运行在特定的操作系统内,例如window,linux,mac等等 #2 运行应用程序,需要要操作...

    Jetpropelledsnake21
  • python基础-字符串与编码

    转载于:廖雪峰的官方网站-python教程 字符编码 我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题。 因为计算机只能处理数字...

    昱良
  • 字符串和编码

    字符编码 我们已经讲过了,字符串也是一种数据类型,但是,字符串比较特殊的是还有一个编码问题。 因为计算机只能处理数字,如果要处理文本,就必须先把文本转换为数字才...

    wangxl
  • UNICODE,GBK,UTF-8

    UNICODE,GBK,UTF-8     简单来说,unicode,gbk和大五码就是编码的值,而utf-8,uft-16之类就是这个值的表现形式.而前面那三...

    lulianqi

扫码关注云+社区

领取腾讯云代金券