Total Pageviews

Wednesday 26 June 2024

Qt跨平台编程之中文编码问题



在使用 Qt5 进行开发的过程中遇到了一些跨平台的中文编码转换问题,然后进行了一番调查,这里做个总结,希望能帮上他人。

字符编码
首先我们认识一下 UNICODE, UNICODE 是由微软等多个知名公司发布的一种字符集标准,具体编码实现有 UTF-8, UTF-16 和 UTF-32 这三种编码格式。而GBK字符编码属于另一套字符集,类似的还有Big5字符集。

然后介绍一下 UCS ,UCS 是 ISO 组织发布的一种类似 UNICODE 的字符集标准,后来两者开始合流,编码基本一致。这里需要知道的是 UCS-2 和 UTF-16 之间的关系,UCS-2 规范相当于 UTF-16 规范的 子集,因为 UTF-16 有扩展字符为变长,而 UCS-2 是固定两个字节。

windows 字符编码
windows 自从 windows 2000 后 就开始使用 UNICODE 字符集,具体编码是 UTF-16 编码。然后从 vista 之后开始支持 UNICODE 5.0 标准,对 UTF-16 的支持也更加完善,支持 UTF-16 surrogate 扩展字符的显示。对于windows的开发人员而言,我们需要知道 windows 上具体代表 UTF-16 编码的数据类型,这里以 visual studio 系列 IDE 和所带的编译器为例,Qt这里也使用了 msvc 编译器环境

    代表 UTF-16 的数据类型是 wchar_t,也就是我们工程设置选择的宽字符。可能有人会问,UTF-16 是变长编码,扩展编码会用到4个字节,wchar_t 怎么表示?遗憾的是的确没法表示,这更像是 UCS-2 标准,但是我们需要知道的是 windows 的内核的确是 UTF-16 的,只是编程接口只提供了两字节的 wchar_t。不过这些扩展字符基本用不到,所以我们不用过多考虑,如果你需要了解更多可以自行查阅资料,博主暂时未深入
    visual studio 创建的源码文件默认是 ANSI 编码,此时 char 字符串是默认的 GBK 编码,微软的开发工具和编译器对 GBK 支持良好
    我们当然也可以设置 visual studio 采用 UTF-8 编码,只需要使用 UTF-8 格式的源码文件,然后在源码中加入下面的预编译宏。这样 char 字符串就默认为 UTF-8 编码了,Qt + msvc 的设置也是如此

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

注意:文件格式使用 UTF-8 可能出现 "error C2001: 常量中有换行符" 的情况,这时候可以改文件格式为 UTF-8 BOM 来解决问题。实际上还有一些其他的解决方案,大家可以自行搜索。

linux 字符编码
linux系统默认使用的 UTF-8 编码,对于linux的开发人员而言,就简单多了,都用 UTF-8 就万事大吉了,这里使用 QtCreator + gcc 来做讲解。
如果我们需要完全使用 GBK 编码来开发也是可以的,需要在 Qt 工程的 main 函数加入下面的设置,并使用 GBK 格式的源文件:

QTextCodec *codec = QTextCodec::codecForName("gbk");
QTextCodec::setCodecForLocale(codec);

Qt5 字符编码
QString 是 UNICODE 编码,确切来说是 UTF-16 编码。Qt程序想正确显示中文,那么就需要把其他编码的字符串转为 UNICODE 编码。然后我们来说一下 QString 的几种构造方式

//这种是默认传入的字符串为 UTF-8
QString strTest = QString("我是");

//这个就是从 UTF-8 字符串构造,和上面一样
QString strTest = QString::fromUtf8("我是");

//这个也是默认字符串为UTF-8
QString strTest = QString::tr("我是");

//这个编码根据系统来,windows就是GBK,linux就是UTF-8
QString strTest = QString::fromlocal8Bit("我是");

//这个就是 ASCII 这种了,单字节的
QString strTest = QString::fromLatin1();

注意:
    QString 是 UTF-16 ,那么 QChar 就和 WCHAR 一样是两个字节
    fromLocal8Bit 是和系统相关的函数,这个函数在windows上,是从GBK 转为 unicode,但是如果是 linux,那么就是从 UTF-8 转为 unicode。所以如果我们需要固定的 GBK 转 UNICODE,那么请采用下面的方式:

QTextCodec* gbkcodec = QTextCodec::codecForName("gbk");
//下面是GBK编码的字符串
const char* bdata = "你好,世界"     
//使用TextCodec库来转换gbk到unicode
QString strGBK = gbkcodec->toUnicode(bdata);

最后我们推荐使用 UTF-8 编码的方式,这样可以方便兼容 windows 和 linux 多平台

参考:https://wiki.qt.io/Strings_and_encodings_in_Qt

No comments:

Post a Comment