一、背景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!