基本概念
字庫表:是一個系統支持的文字,符號,數字的集合。
編碼字符集(字符集):計算機是以二進制的形式存儲字符的,每個字符對應的二進制編碼不同,而編碼字符集就是所有編碼與字符的映射集合。例如:在ASCII碼的編碼字符集中,字母A的編碼是65,65的二進制就是01000001。
字符編碼:不同字符的編碼不同,其二進制的位數也不同。爲了達到節省空間,解析方便等目的,出現了多種存儲字符編碼的方式,每種方式對應一套算法,這套算法也稱字符編碼。例如Unicode字符集,utf-8,utf-16字符編碼。
源文件字符集:源文件本身也是文本文件,所以源文件字符集是指源文件保存時採用哪種字符編碼。
執行字符集:可執行應用程序內使用何種字符編碼。編譯器會將源碼字符集轉換爲執行字符集。
情況一
軟件平臺:Windows 10,Qt Cretor 4.7.2,
問題描述:運行一個基於QT框架的的GUI應用程序時,界面上的PlainTextEdit組件無法正常顯示中文形式的QString字符串,此外,在控制檯中,也無法正常輸出中文形式的QString字符串,即都出現了中文亂碼。如下所示:
void Dialog::on_pushButton_clicked()
{//QHostInfo獲取主機信息
QString hostName=QHostInfo::localHostName(); //本地主機名
ui->plainTextEdit->appendPlainText("本機主機名:"+hostName+"\n");
QHostInfo hostInfo=QHostInfo::fromName(hostName); //本機IP地址
QList<QHostAddress> addList=hostInfo.addresses(); // IP地址列表
if(!addList.isEmpty())
for(int i=0;i<addList.count();i++)
{
QHostAddress aHost=addList.at(i); //每一項是QHostAddress
bool show=ui->checkBox->isChecked(); //只顯示IPv4
if(show)
show=(QAbstractSocket::IPv4Protocol==aHost.protocol()); //IPv4協議
else
show=true;
if(show)
{
ui->plainTextEdit->appendPlainText("協議:"+protocolName(aHost.protocol()));
ui->plainTextEdit->appendPlainText("本機IP地址:"+aHost.toString());
ui->plainTextEdit->appendPlainText("");
}
}
}
QString hello="中文";
qDebug()<<hello;
QString顯示中文亂碼的原因
QString的內部採用unicode字符集,utf-16編碼。構造函數QString::QString(const char *str)默認使用fromUtf8()將str所指的執行字符集從utf-8轉碼成utf-16。由fromUtf8()可知,QString需要執行字符集編碼爲utf-8,然後以utf-8進行解碼,再編碼爲utf-16才能獲得正確的字符編碼。所以,顯示中文亂碼的原因爲:QString的轉碼方式與執行字符集不一致。(比如,源文件字符集爲本地字符集GBK編碼,QString以utf-8的方式進行解碼,會導致獲得錯誤的二進制編碼,再將錯誤二進制轉爲utf-16就會出現亂碼。)
注意:
1.當Qt 5.11.3 MinGW 32bit編譯程序的時候,會分析源代碼文件採用何種編碼,有BOM標識符則可以正確識別其編碼,若沒有BOM標識符則認爲其使用本地字符編碼local字符集。此處使用的windows 10的本地字符編碼爲GBK編碼。
2.編譯器分析出源文件字符編碼之後,會進行解碼再編碼,將源字符集轉碼成執行字符集。執行字符集一般默認爲使用本地字符編碼local字符集,也可以進行設置。
中文亂碼測試
在GUI應用程序的主函數裏創建一個QString對象hello,因爲QString構造函數內部調用了QString::fromUtf8(),所以hello和QString::fromUtf8(“中文”)的表現應該是一致的。QString::fromLocal8Bit()將執行字符集以本地編碼轉爲utf-16。如下爲具體代碼:
#include "dialog.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Dialog w;
w.show();
QString hello="中文";
qDebug()<<hello;
qDebug()<<QString::fromUtf8("中文");
qDebug()<<QString::fromLocal8Bit("中文");
return a.exec();
}
例1:源文件代碼的編碼字符集爲GB2312(Simplified),程序結果如下:
結果表明,前兩種發生了亂碼,fromLocal8Bit()顯示正常。源代碼文件的源文件代碼的編碼字符集爲GB2312(Simplified),不帶BOM標識,因此編譯器會認爲源代碼文件的編碼爲操作系統的本地編碼,而源代碼文件的編碼的確與本地編碼一致,所以fromLocal8Bit顯示正常。因爲fromUtf8將執行字符集以utf-8進行解碼,顯示亂碼。
例2:源文件代碼的編碼字符集爲UTF-8,程序結果如下:
結果表明,前兩種顯示正常,fromLocal8Bit()發生了亂碼。源代碼文件的源文件代碼的編碼字符集爲UTF-8,不帶BOM標識,因此編譯器會認爲源代碼文件的編碼爲本地編碼,執行字符集也是本地編碼,因此不會進行轉碼,但實際上執行字符集是utf-8編碼。因此fromUtf8將執行字符集以utf-8進行解碼,顯示正確;而fromLocal8Bit將執行字符集以本地編碼進行解碼,顯示亂碼。
解決方案
由於程序的源代碼文件採用的編碼方式是GB2312(Simplified),不帶BOM標識,因此編譯器會認爲源代碼文件的編碼爲操作系統的本地編碼,而源代碼文件的編碼的確與本地編碼一致,所以fromLocal8Bit顯示正常。所以解決中文亂碼問題的方法是:程序中凡是用到中文的地方都以QString::fromLocal8Bit(“中文”)的形式出現。如下爲改進後的程序結果:
情況二
軟件平臺:Windows 10,Qt Creator 4.7.2,CMake 3.13.4
問題描述:運行一個含有中文輸出的cmake項目時,在控制檯中輸出的都是中文亂碼。出現中文亂碼的原因在於,中文版的Windows平臺支持的是GB2312的編碼格式,而Qt Creator默認使用的則是Linux下通用的UTF-8編碼格式,然後,基於Windows平臺的程序控制臺再用GB2312編碼格式
來解釋本是UTF-8格式的中文輸出
,進而就因爲兩者的編碼格式的不同導致了中文亂碼的輸出。解決問題的思路爲,一是改變Windows系統的編碼格式爲UTF-8
,二是把Qt Creator的默認編碼格式改爲GB2312
。下面的解決方案遵循思路二。
解決方案:工具=>選項=>文本編輯器=>行爲,把文件編碼
那一塊中的默認編碼設爲:GB2312
,然後點擊Apply
,再點擊OK
把編輯器的默認編碼改爲GB2312
後,還要注意一些事項才能輸出中文,注意事項如下:
-
把代碼
string a="你好,中文!";
中的中文去掉,如string a="";
,其他的也可以,只要保證代碼中沒有中文即可 -
進入項目所在的目錄,把構建目錄
build
和項目文件CMakeLists.txt.user
刪除掉
-
通過
Qt Creator
打開文件CMakeLists.txt
重新構建CMake項目HelloWorld
,然後把之前的代碼改回來,即把string a="";
改爲string a="你好,中文!";
。如此,在控制檯中輸出的中文就不再是亂碼了