QT输出中文乱码深刻剖析

总结:

1.
qt输出普通话乱码原因剖析

qt的编制程序环境暗中同意是utf-8编码格式(至于编码见下文知识要点一);

cout << "中文" << endl;

程序运营,程序并不认识ANSI,UTF-8以及其余其余编码.系统只通晓处理你给它的字符的**二进制表示.**

 

有关  “中””文”
的3种编码二进制内容:

 

ANSI(GBK): 0xd6d0  0xcec4

 

UTF-8: 0xe4b8ad 0xe69687

 

Unicode: 0x4e2d 0x6587

1)在简体汉语Windows下的控制台展现环境是ANSI编码(代码页936,
GBK),先明了那一点.

关键差别,MinGW看到的是”0xe4b8ad”和”0xe69687″(gcc私下认可UTF-8).注意,用MinGW编写翻译的源文件中有汉语宽字符必须保留为UTF-8编码.

2)测试代码:

#include <iostream>
using namespace std;

int main()
{
    char a[] = "中文";
    cout << a << endl;
    return 0;
}

3)经在qt5.第88中学测试乱码;

解析:参见(下文知识要点一,知识要点二)不难察觉UTF-陆只是一种编码进行方案,并不是实际上编码;再参见(知识要点五),程序运维是能过最终编译实现的二进制码输出

在vs2017中,用unicode编码方式,编写翻译运转输出平常;原因作者想很好驾驭了,当程序编写翻译后保存的是“普通话”unicode二进制编码,而控制台出口时CodePage
(GBK 936)
那些CodePage就会基于映射表去挨家挨户对应GBK中的中文字,再拓展输出;

而在qt5.8(MinGW)中,输出则是乱码;因为qt5.8私下认可的编码格局是UTF-8;当程序编写翻译后保存的是“普通话”UTF-8二进制编码,而决定台出口时CodePage
(GBK 936)
那些CodePage就会依据映射表去各类对应GBK中的普通话字,好像哪个地方不对,好了,问题就出在这时了,CodePage是各国与unicode的映射表,并不是与UTF-8的(知识要点二CodePage),在qt5.8(MinGW)中,原程被编写翻译二进制文件,保存下去的“普通话”地址是,UTF-8编码,而映射表是在unicode中找内容,再开展输出,自然正是乱码;

网上消除办法1.改动注册表CodePage 65001  经测试还是乱码

反驳分析:CodePage(GBK
936)找不到映射,那么把控制台换到UTF-8;那么然先保存的,UTF-8汉语,再通过UTF-8对应的汉字码,不就能出口汉字;理论好像可行,但在自笔者的win7
陆十一位中国语言管法学系统上,qt5.8,vs2017均失败;

恐怕原因:笔者系统中cmd控制台并不帮衬UTF-8编码格局(有空子在win第10中学测试后再做补充)

化解方法2:通过(知识点一,二,
五),总括,当要在支配台举办粤语输出时,编码方式应该保留为unicode,或ACSI(GBK);

4)关于宽字节出口乱码的标题;

出口宽字节中文(详见文化要点四):例

#include <iostream>
using namespace std;

int main()
{
    wcout << L"中文" << endl;
    return 0;
}

输出则要用wcout而不可能是cout;关于宽字符详见;文化要点二后续,**知识要点三**

在vs2017中,输出中文,为空;

1、cout和wcout

 在C++下,cout能够一向出口汉语,但对于wcout却卓殊。对于wcout,要求将其locale设为地面语言才能出口汉语:

 wcout.imbue(locale(locale(),””,LC_CTYPE));

 也有人用如下语句的,但那会改变wcout的装有locale设置,比如数字“1234”会输出为“1,234”。

 wcout.imbue(locale(“”));

 在C语言下,locale设置为地点语言(C语言中只有全局locale)就足以健康输出了:

 setlocale(LC_CTYPE, “”);

 在qt5.8(MinGW)环境中,以上并不实用,近年来还没找到出口汉语的不二法门,未完待续;

 

文化要点一:编码**

ASCII:
早期的字符集,6位,1三十个字符,包涵大小写a-z字母,0-9数字以及一些说了算字符.

  扩展ASCII: 3个字节五个人,只用7个人不合理.于是第10个人用于扩张ASCII字符集,那样就又多了1二十六个字符.于是用着后1三十个字符来扩大表示如拉丁字母,希腊(Ελλάδα)字母等特殊符号.但难题是亚洲那一票国家很多并行都拥有不等同的出色字母,一起塞进后1三十多少个显然不够,于是代码页现身了.

**  Code Page(代码页)**:
一个字节前1叁拾一个字符大家集合和ASCII一样,而后1二十九个字符,根据不一样系统所谓代码页来区分各样语言不一致等的假名和符号.

**  DBCS(双字节字符集)**:
对于澳洲国度,后126个字符照旧不知所厝包涵大批量的象形文字,DBCS就是为此的二个化解方案.DBCS由2个或七个字节表示三个字符,那评释DBCS并不一定是多个字节,对于如英文字母,是向ASCII包容的,仍然由三个字节表示,而对此如中文则用一个字节表示.英文和国文可以统一地处理,而区分是还是不是为汉语编码的章程是一个字节中的高字节的第一个人为1,就务须检查前边紧跟着的不胜字节,二个字节一起解释为1个字符.GB2312,GBK到GB18030都属于DBCS.其余,简体中文Windows下的ANSI编码平日是指GBK(代码页936).

DBCS不小题材在于字符串的字符数无法通过字节数来决定,如”普通话abc”,字符数是5,而字节数是7.对于用++或–运算符来遍历字符串的程序员来说,那差不多就是惊恐不已的梦!

  Unicode: 学名为”Universal Multiple-Octet
Coded Character Set
“,简称”UCS“.UCS能够看成是”Unicode Character
Set”的缩写.

也是一种字符集/字符编码方法,它统一用唯一的字符集来含有那些星球上绝超越55%言语的书写系统.UCS向ASCII包容(即前1二十六个字符是同等的),但并不一致盟DBCS,因为此外字符在UCS中被另行编码(重新布署地点).

UCS有二种格式:UCS-2和UCS-4.前者用一个字节(15位)编码,后者用伍个字节(实际上只用叁拾肆个人)编码.USC-4前二个字节都为0的一部分号称BMP(基本多语言平面),正是说BMP去掉前1个零字节正是UCS-2.如今的UCS-4规范中还一贯不别的字符被分配在BMP之外.(说白了,USC-4正是为当1九个人的USC-2都被分配完时候做再做扩大用的,以往还没用到)

  UTF-8,UTF-16,UTF-32: “Unicode transformation
format”(UTF)
 ,即Unicode的传输格式.Unicode规定了怎么编码字符,而UTF规定怎么将三个Unicode字符单元映射到字节序来传输或保存.

UTF-16UTF-32个别表示以1几人和叁十四位为三个Unicode单元举办编码,其实UTF-16对应正是UCS-2,UTF-32对应正是UCS-4(UCS-2和UCS-4是陈旧的说教,应捐弃).
别的,平日说的Unicode正是指UTF-16.

UTF-8是关键!若是统一Unicode都用2字节代表,英文字母觉得温馨就很吃亏(高字节始终是0字节).UTF-8提供了一种灵活的消除办法:以单字节(8bit)作为编码单元,变长多字节编码情势.如ASCII字母继续运用1字节储存,粤语汉字用3字节储存,其余最多可直6字节.

UTF-16和UTF-32供给有字节序标志BOM(FEFF)解决大端小端难点.UTF-8没有字节序的题材(因为以3个字节为单元).

 

===============================================================================

任何注意点:

DBCS准确说,应该是MBCS(Multi-Byte Chactacter
System, 多字节字符系统).

字符集(Charset)和编码(Encoding)注意分裂.如GBK,GB2312以及Unicode都既是字符集,也是编码格局,而UTF-六头是编码形式,并不是字符集.

Linux下The GUN
C Library(从glibc
2.2起来)中宽字符wchar_t是以叁拾几人的Unicode(USC-4)表示.如宽字符”中”字为
“0x00004e2d”.而Windows下的CRT使用宽字符仍是十几人的.

 

文化要点二:关于Unicode的咀嚼(加深对编码的精晓)

析Unicode和UTF-8 

壹 、首先说美赞臣(Meadjohnson)下现行常用的局地编码方案:
1.
在炎黄,大陆最常用的就是GBK18030编码,除此之外还有GBK,GB2312,那多少个编码的涉及是那样的。
最早制定的汉字编码是GB2312,包涵6762个汉字和68一个别的符号
95年重新修订了编码,命名GBK1.0,共收音和录音了2188陆个标志。
之后又推出了GBK18030编码,共收音和录音了274八十几个汉字,同时还引用了藏文、蒙文、维吾尔文等根本的少数民族文字,今后WINDOWS平台必须求辅助GBK18030编码。
遵从GBK18030、GBK、GB2312的次第,3种编码是向下兼容,同三个汉字在四个编码方案中是平等的编码。
2.  湖北,香岛等地动用的是BIG5编码
3.  日本:SJIS编码
二、Unicode
  假如把种种文字编码形容为四方的白话,那么Unicode正是世界各国营商业和供应和销售合营社作开发的一种语言。
  在那种语言环境下,不会再有语言的编码争持,在同屏下,能够显示别的语言的始末,这正是Unicode的最大益处。
  那么Unicode是什么编码的啊?其实分外简单。
  正是将世界上具有的文字用2个字节统一举行编码。可能你会问,2个字节最多能够代表65537个编码,够用呢?
  南韩和东瀛的多数中华夏族民共和国字都以从中华夏族民共和国流传过去的,字型是全然一致的。
  比如:“文”字,GBK和SJIS中都是同二个汉字,只是编码差异而已。
  那样,像这么统一编码,2个字节就已经充裕容纳世界上独具的言语的超过1/4文字了。
UCS-2 与UCS-4
  Unicode的学名是”Universal Multiple-Octet Coded Character
Set”,简称为UCS。
  今后用的是UCS-2,即2个字节编码,而UCS-4是为着防患今后2个字节不够用才开发的。UCS-2也称之为基本多文会平面。
  UCS-2转换成UCS-四只是简单的在头里加2个字节0。
  UCS-4则珍视用于保存援救平面,例如Unicode 4.0中的第三声援平面
  20000-20FFF – 21000-21FFF – 22000-22FFF – 23000-23FFF – 24000-24FFF

  • 25000-25FFF –   26000-26FFF   - 27000-27FFF – 28000-28FFF –
    29000-29FFF – 2A000-2AFFF – 2F000-2FFFF
      总共扩张了十五个帮忙平面,由原本的65537个编码扩张至邻近100万编码。
    三、 兼容codepage
      那么既然统一了编码,如何合作原先各国的文字编码呢?
      那几个时候就须求codepage了。
      什么是codepage?codepage正是各国的文字编码和Unicode之间的映射表。
      比如简体普通话和Unicode的映射表正是CP936,点那里查看合法的映射表。
      以下是多少个常用的codepage,相应的修改下面的地点的数字即可。
      codepage=936 简体中文GBK
      codepage=950 繁体粤语BIG5
      codepage=437 花旗国/加拿大阿拉伯语
      codepage=932 日文
      codepage=949 韩文
      codepage=866 俄文
      codepage=65001 unicode UFT-8
    末尾二个65001,据个人精晓,应该只是1个虚构的映射表,实际只是三个算法而已。
    从936中专断取一行,例如:
    0x9993 0x6ABD #CJK UNIFIED IDEOGRAPH
    前方的编码是GBK的编码,前边的是Unicode。
    通过查那张表,就能不难的实现GBK和Unicode之间的变换。
    四、UTF-8
      以后知晓了Unicode,那么UTF-8又是怎么吗?又何以会现出UTF-8呢?
      ASCII转换来UCS-2,只是在编码前插入2个0x0。用这么些编码,会包含部分控制符,比如
    ” 或
    ‘/’,那在UNIX和部分C函数中,将会发生严重错误。由此能够肯定,UCS-2不符合当作Unicode的表面编码。
      由此,才出生了UTF-8。那么UTF-8是什么编码的?又是什么缓解UCS-2的题材吧?
    例:
    E4 BD A0        11100100 10111101
    10100000
    这是“你”字的UTF-8编码
    4F 60          01001111
    01100000
    这是“你”的Unicode编码
    有关汉字依照UTF-8的编码规则,分解如下:xxxx0100 xx111101 xx一千00
    把除了x之外的数字拼接在一块儿,就变成“你”的Unicode编码了。
    注意UTF-8的最前边3个1,表示全体UTF-8串是由3个字节构成的。
    通过UTF-8编码之后,再也不会出现敏感字符了,因为最高位始终为1。
    以下是Unicode和UTF-8之间的更换关系表:
    U-00000000 – U-0000007F: 0xxxxxxx
    U-00000080 – U-000007FF: 110xxxxx 10xxxxxx
    U-00000800 – U-0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
    U-00010000 – U-001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
    U-00200000 – U-03FFFFFF: 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    U-04000000 – U-7FFFFFFF: 1111110x 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
    10xxxxxx、
    Unicode编码转换来UTF-8,针对汉语,简单的把Unicode字节流套到x中就成为UTF-8了。

续篇:

unicode在windows api中的应用
    实际上,常提到的Win32
API的称号并不是它们的实际名称。那一个名称仅仅是一对宏,你能够在PSDK的头文件中找到这么些宏对用的函数名称。所以,假若PSDK的文书档案提到1个函数,如CreateFile,开发职员应该发现到它惟有是一个宏。它的真实性名称是CreateFileA和CreateFileW。是的,它意味着了“四个”函数名,而不是二个,是同一个函数在分裂Win32函数的七个例外的本子。以’A’结尾的函数接受ANSI字符串(char *),即Unicode字符串(wchar_t
*)而在vs中可以用WCHAENCORE宏代替,即wchar_ts型字符串。二种版本的函数都在模块kernel32.dll中完成,借使您的编制程序环境是Unicode则,则宏CreateFile在编写翻译是会被CreateFileW代替,不然用CreateFileA代替。

PSDK的字符串化解方案:TCHA途睿欧s
   
为了防止为不一致的windows操作系统开发不一致版本的PSDK,微软制订了2个集合的字符串类型TCHARAV4s。TCHALacrosse以及其它的相应的宏在头文件WinNT.h中有定义。程序员在程序中不须求为使用char还是wchar_t而纠结,只供给选取宏TCHA揽胜极光就足以了。按照Unicode环境是或不是留存,编译器会活动举行相应的转换。同样道理,程序员不供给为运用’A’依然’W’型Win32
API函数纠结。

对此较早先时代的系统均使用ACSI编码,而在风行系统中则都统一为unicode编码(如:手提式有线电话机系统)

 

知识要点三:
L”……”,
_T(), _TEXT
,TEXT()

L”……”: L是意味着字符串财富转为宽字符的保留(常常转为unicode),却未必是unicode字符,那与编写翻译器达成相关。

_T(” ……”) 是贰个适配的宏     #ifdef _UNICODE(当系统环境是unicod下)
_T正是L   而当系统环境是ACSI 
_T便是ANSI的。(有便利早期windows系编制程序文件的移植,达到新旧类别互相)

_T、_TEXT、TEXT 三者效果等同

tchar.h是运维时的头文件,_T、_TEXT 根据_UNICODE来鲜明宏
winnt.h是Win的头文件根据,TEXT 依据UNICODE 来鲜明宏

比方需要同时选择那二个宏,则需同时定义 UNICODE 和 _UNICODE
VS二〇〇九随后的版本中
,设置:项目–属性–配置属性–常规–字符集–使用Unicode字符集,
那么编写翻译器命令选项中真的同时参加了_UNICODE和UNICODE。

知识要点四: c++ 的cout 与
wcout**

cout << "hello world!" << endl; //ACSI 编码输出

cout << L“hello world!” <<endl;// unicode 输出

当输出双字节编码到控制台时,cout输出的将是地点而不要内容那时就要用到wcout;

改为:

cout << "hello world!" << endl; //ACSI 编码输出

wcout << L“hello world!” <<endl;// unicode 输出

** 


知识要点五:编写翻译连接进程

1.预处理 生成.i文件

C++的预处理是指在C++程序源代码被编写翻译在此以前,由预处理器对C++程序源代码进行的处理。那几个进度并不对程序的源代码举行剖析。

那里的预处理器(preprocessor)是指真的的编写翻译起头从前由编译器调用的叁个独立程序。

预处理器首要承担以下的几处

1.宏的更迭

2.剔除注释

3.拍卖预处理指令,如#include,#ifdef

 2.编译和优化 生成汇编.s原文件

词法分析 — 识别单词,确认词类;比如int
i;知道int是2个门类,i是二个关键字以及判断i的名字是或不是合法
语法分析 — 识别短语和句型的语法属性;

语义分析 — 确认单词、短语和句型的语义特征;

代码优化 — 修辞、文本编辑;

国家地理,代码生成 — 生成译文。

3.生成**.o**指标文件


汇编进程实际上指把汇编语言代码翻译成目的机器指令的长河。

在结尾的指标文件中

除却有着自身的数量和二进制代码之外,还要至少提供1个表:未缓解符号表和导出符号表,分别报告链接器自身须要如何和能够提供哪些。

编写翻译器把八个cpp编写翻译为目的文件的时候,除了要在目的文件里写入cpp里含有的数目和代码,还要至少提供2个表:未缓解符号表,导出符号表和地址重定向表。
未缓解符号表提供了富有在该编写翻译单元里引用不过定义并不在本编写翻译单元里的记号及其现身的地点。
导出符号表提供了本编写翻译单元具有定义,并且愿意提须要任何编写翻译单元使用的标志及其地址。
地方重定向表提供了本编写翻译单元全数对本人地址的引用的笔录。

4.链接

由汇编制程序序生成的对象文件并不能登时就被实施,在那之中可能还有众多不曾化解的难点。例如,有个别源文件中的函数只怕引用了另多少个源文件中定义的有些符号(如变量或许函数调用等);在先后中也许调用了有些库文件中的函数,等等。全体的那一个题材,都亟待经链接程序的处理方能得以消除。

 

相关文章