zoukankan      html  css  js  c++  java
  • Qt5程序参数包含中文GBK编码的问题

    1、背景

    Qt5程序(WeekReport.exe)的main函数里有如下代码:

    //only for test

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);

        if ((argc <= 1) || !QFileInfo::exists(argv[1]))
        {
            qDebug() << "argc is " << argc << "; " << "argv[1] is : " << argv[1] << "; "   << "Set default dir.";
            QDir::setCurrent("D:/测试部管理/公司例行会议/研发中心周例会/部门周报表/20141107");
        }
        else 
        {
            qDebug() << "Set dir: " << argv[1];
            QDir::setCurrent(argv[1]);
        }
    }
    //end test

    代码主要的功能是判断传入的目录参数是否有效:如果有效则设置为当前路径,否则设置为默认路径。

    2、问题

    程序编译链接完成后,用批处理脚本进行调用,如下:

    WeekReport.exe "D:/测试部管理/公司例行会议/研发中心周例会/部门周报表/20141117" /f

    结果输出如下:

    argc is  3 ;  argv[1] is :  D:/?????????/??????л???/?з???????????/?????????/20
    141117 ;  Set default dir.

    很显然,程序遇到了Encode编码问题,而且看起来和传入参数的中文字符串有关。

    3、追踪和解决

       好在Qt开源,对代码进行跟踪:

       if ((argc <= 1) || !QFileInfo::exists(argv[1]))

       exists的原型为: bool QFileInfo::exists(const QString & file) [static]

       1)实际传入的参数为GBK编码

       首先调用Qstring的构造函数,如下:

            image

        由图可知,传入的参数argv[]类型为char*,该类型不考虑字符串的编码格式。进一步查看该字符串的内存地址0x012f6f72:

            image

       通过工具可以看出,内存中的字符串编码为GBK格式。证据如下:

           a)GBK格式字符串对应的二进制内容显示

            image

            b)相同GBK格式字符串对应的GBK编码内容显示

            image

         由此可知,argv参数在作为char*类型进行传入时,内存中保存的是GBK编码。

      2)Qt将传入参数理解为Utf-8编码

    在构造函数里调用了fromAscii_helper()函数,如下:

    QString::Data *QString::fromAscii_helper(const char *str, int size)
    {
        QString s = fromUtf8(str, size);
        s.d->ref.ref();
        return s.d;
    }

    注意fromUtf8函数,看起来,Qt是准备将传入的char*字符串参数当作UTF-8格式进行转换后,在内部作为Unicode格式进行使用。果然如此:

    static inline QString fromUtf8(const char *str, int size = -1)
        {
            return fromUtf8_helper(str, (str && size == -1) ? int(strlen(str)) : size);
        }
    QString QString::fromUtf8_helper(const char *str, int size)
    {
        if (!str)
            return QString();
    
        Q_ASSERT(size != -1);
        return QUtf8::convertToUnicode(str, size);
    }

    以上就是Qt对传入字符串的编码转换处理。可以通过2个名字来理解:fromUtf8、convertToUnicode,即将传入的字符串当作UTF-8格式,最终转换为Unicode格式。

      3)如何解决

    由1)和2)可以看出问题点在于传入参数的字符编码格式和Qt要求的不一致。因此解决的方案是要么调整传入参数的字符编码格式,要么调整Qt的要求。

    Qt库不能改,windows记事本字符编码和保存格式也不能改,只能在应用程序中进行修改:帮助Qt识别传入参数的字符编码。如下

    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
        if ((argc <= 1) || !QFileInfo::exists(QString::fromLocal8Bit(argv[1])))
        {
            qDebug() << "argc is " << argc << "; " << "argv[1] is : " << QString::fromLocal8Bit(argv[1]) << "; "   << "Set default dir.";
            QDir::setCurrent("D:/测试部管理/公司例行会议/研发中心周例会/部门周报表/20141107");
        }
        else 
        {
            qDebug() << "Set dir: " << QString::fromLocal8Bit(argv[1]);
            QDir::setCurrent(QString::fromLocal8Bit(argv[1]));
        }
        //
    }

    注意红色字体代码,将输入字符串作为本地编码进行转换,而不是作为UTF-8编码进行转换;另外,windows默认的本地编码为GBK。输出结果为:

    Set dir:  "D:/测试部管理/公司例行会议/研发中心周例会/部门周报表/20141117"

    ok!

  • 相关阅读:
    codevs 2632 非常好友
    codevs 1213 解的个数
    codevs 2751 军训分批
    codevs 1519 过路费
    codevs 1503 愚蠢的宠物
    codevs 2639 约会计划
    codevs 3369 膜拜
    codevs 3135 River Hopscotch
    数论模板
    JXOJ 9.7 NOIP 放松模拟赛 总结
  • 原文地址:https://www.cnblogs.com/lustforlife/p/4104335.html
Copyright © 2011-2022 走看看