一、背景html
Qt5程序(WeekReport.exe)的main函数里有以下代码:windows
//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
代码主要的功能是判断传入的目录参数是否有效:若是有效则设置为当前路径,不然设置为默认路径。工具
二、问题测试
程序编译连接完成后,用批处理脚本进行调用,以下:字体
WeekReport.exe "D:/测试部管理/公司例行会议/研发中心周例会/部门周报表/20141117" /f
结果输出以下:编码
argc is 3 ; argv[1] is : D:/?????????/??????л???/?з???????????/?????????/20 141117 ; Set default dir.
很显然,程序遇到了Encode编码问题,并且看起来和传入参数的中文字符串有关。spa
三、追踪和解决code
好在Qt开源,对代码进行跟踪:htm
if ((argc <= 1) || !QFileInfo::exists(argv[1]))
1)实际传入的参数为GBK编码
首先调用Qstring的构造函数,以下:
由图可知,传入的参数argv[]类型为char*,该类型不考虑字符串的编码格式。进一步查看该字符串的内存地址0x012f6f72:
经过工具能够看出,内存中的字符串编码为GBK格式。证据以下:
a)GBK格式字符串对应的二进制内容显示
b)相同GBK格式字符串对应的GBK编码内容显示
由此可知,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个名字来理解:fromUtf八、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!