关于char wchar_t 和 unicode utf8等总是混淆概念。

时间:2021-10-12 20:19:49
关于unicode utf8 gb2312等前一阵看过了,大概感觉明白了。
但是最近看ogre的tinyxml的代码,里面都是用char读、写的。
但是,却支持中文,但是需要一个转换。
通过下面文章,我解决了问题,获得了中文。然后,我发现我又晕了。

C+++Utf8字符转换Gb2312编码,解决TinyXml中文乱码 
http://blog.csdn.net/xionghaoaizhangruyun/article/details/6768362

这些概念我就越来越晕了。
google半天,没有说char为啥能够支持中文。
所以我来问问,谁给讲讲这些都是怎么回事。

PS:关于字符编码简介:ASCII,Unicode,UTF-8,GB2312等的有很多,就不用麻烦赘述了。
关键是为啥char支持中文啊?而且,char wchar_t的区别是?和上面这些字符编码的区别是?

我就没明白过。

期待中。

15 个解决方案

#1


发错地方了?版主帮帮忙给转一下位置吧。傻掉了,发地方了。可能

#2


char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。补充说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。 

刚刚看到上面这段,摘过来。很晕。我的项目 是C++,字符设置为unicode,那么char就是两个字节?!
char不是一个字节的吗?上面时候改了?

#3


该回复于2012-07-03 08:26:34被版主删除

#4


通知说有人回复了?我看不到……

#5


对电脑而言没有乱码,只有二进制字节;对人脑才有乱码。

推荐使用WinHex软件查看文件或内存中的原始字节内容。

VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)

提醒:
“学习用汇编语言写程序”

“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)”
不是一回事!

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

#6


char wchar_t这两个是数据类型,一个是宽字节,一个是窄字节,其本身存储的是0xXX 或 0xXXXX(并不包含解释,只说明这些内存中的东西要用字符型或宽字节字符型进行解释)
Unicode和utf-8是编码方式,是用来解释内存中字符型或宽字节字符型数据0xXX或0xXXXX是什么的是英文"XXOO"啊还是中文"酱油"啊的作用,不能把两者混为一谈

#7


坛子里明白的没几个人,你要是特别想了解可以加我QQ。

#8


引用 5 楼  的回复:
对电脑而言没有乱码,只有二进制字节;对人脑才有乱码。

推荐使用WinHex软件查看文件或内存中的原始字节内容。

VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后……

看来还挺麻烦的。我去看看。十分感谢

#9


引用 6 楼  的回复:
char wchar_t这两个是数据类型,一个是宽字节,一个是窄字节,其本身存储的是0xXX 或 0xXXXX(并不包含解释,只说明这些内存中的东西要用字符型或宽字节字符型进行解释)
Unicode和utf-8是编码方式,是用来解释内存中字符型或宽字节字符型数据0xXX或0xXXXX是什么的是英文"XXOO"啊还是中文"酱油"啊的作用,不能把两者混为一谈


你的想法和我的差不多。但是我不确定。你有什么确定的手段吗?
我感觉5楼的手段可行。

#10


首先,内存中的数据是单纯的二进制数据,当然你要用十六进制来表示它也可以
不管你用什么指针指向这段内存,数据就是数据,不会有任何改变
你是用char*也好,用int*也罢,甚至用string*都一样,它们都只是指针,类型+地址而已,和它们指向的那段内存的数据没有任何关系——当然在使用中一般是有关系的,否则就是写代码的人有问题了

其次,中文是什么?英文是什么?日文是什么?
全部都是符号,全部都是概念,落在纸面上全部都是图形
和二进制有关系?一丁点的关系都没有

那么,什么是字符集?
规定二进制数据和某种语言内的文字之间的对应关系,这就叫该种语言的字符集
最基本的是ASCII,规定数值48对应字符'0',诸如此类,但由于这种对应关系的历史局限性(发明它的人当时没兴趣考虑非英文语言),同样的二进制数据,在不同的字符集内就对应不同的文字
而规定一套对应关系,使得二进制数据能够对应很多语言的文字,这就叫Unicode

unicode和utf8等等格式,本质上是不同的对应关系
char*可以用来指向各种数据的内存,不是因为它们都是char字符数据,而是因为char的大小是1个字节,方便指针控制(如果你要用void*指向各种内存,概念上是更加正确了,你试试看怎么偏移指针)
wchar_t其实就是typedef的2字节short,也就是对应unicode的编码范围为2字节数据,用的就是这种数据类型的字节数而已
所以char*和wchar_t*指向同一段内存,有什么错?一点错误都没有,它们都只指向这一段二进制数据而已,区别就在于你使用这两种类型的指针来操作数据的时候,按照相应的类型来操作这段内存,仅此而已

还有什么问题吗?

#11


google半天,没有说char为啥能够支持中文。

——按你的说法,char可以“支持”任何类型的变量,因为它们都是以字节为基本单位的二进制数据
——不是char支持中文,而是char*可以指向一段存有二进制数据的内存,这段内存中的数据按照某种对应关系对应中文的文字集合,而你用来显示文字的显示模块也按照这种对应关系来转换二进制数据到文字相关属性(文字图形等)
——所以正确的说法是,你用来显示/处理文字的函数/模块,支持中文这个文字集合,以及你所选择的unicode这种对应关系

#12


wchar_t unicode[1]=L'汉';//0x49 0x6c ;Little endian unicode 0x6c49
//UTF-8 编码字符理论上可以最多到 6个字节长,但目前全世界的所
//有文字和符号种类加起来也只要编到 4个字节长就够了。
//  UTF-8 是以 8位(即 1个字节)为单元对原始码进行编码(注意一
//点:这里所讲的原始码都是指Unicode码),并规定:多字节码(2个字
//节以上才称为多字节)以转换后第1个字节起头的连续“1”的数目(这
//些连续“1”称为标记位),表示转换成几个字节:“110”连续两个
//“1”,表示转换结果为2个字节,“1110”表示3个字节,而“11110”
//则表示4个字节……跟随在标记位之后的“0”,其作用是分隔标记位和
//字符码位。第2~第4个字节的起头两个位固定设置为“10”,也作为标
//记,剩下的6个位才做为字符码位使用。
//  这样,2字节UTF-8码剩下11个字符码位,可用以转换0080~07FF的
//原始字符码,3字节剩下16个字符码位,可用以转换0800~FFFF的原始字
//符码,由此类推。编码方式的模板如下:
//
//原始码(16进制) UTF-8编码(二进制)
//--------------------------------------------
//0000 - 007F       0xxxxxxx
//0080 - 07FF       110xxxxx 10xxxxxx
//0800 - FFFF       1110xxxx 10xxxxxx 10xxxxxx
//……
//--------------------------------------------
//
//  模板中的“x”表示字符码。
//  VB能识别的 Ascii码<007F,所以在VB中,Ascii码都只能编为1个
//字节的UTF-8码。汉字的 Unicode编码范围为0800-FFFF,所以被编为
//3个字节的UTF-8码。
//  例如“汉”字的Unicode编码是6C49,6C49在0800-FFFF之间,所以
//要用3个字节的模板:1110xxxx 10xxxxxx 10xxxxxx。
//1110xxxx 10xxxxxx 10xxxxxx
//11100110 10110001 10001001 0xE6,0xB1,0x89
//    0110   110001   001001
//0110110001001001 0x6c49
char utf8[3]={0xE6,0xB1,0x89};//utf8 汉

#13


引用 11 楼  的回复:
google半天,没有说char为啥能够支持中文。

——按你的说法,char可以“支持”任何类型的变量,因为它们都是以字节为基本单位的二进制数据
——不是char支持中文,而是char*可以指向一段存有二进制数据的内存,这段内存中的数据按照某种对应关系对应中文的文字集合,而你用来显示文字的显示模块也按照这种对应关系来转换二进制数据到文字相关属性(文字图形等)
——所以正确的说法是,你用……

不是char支不支持中文的问题,char只是存储空间只有1个字节,中文至少要2个字节,必然存不下,char字符串中你用utf-8编码,输出出来的还是那些字符还是utf-8必然没问题。
你可以不去想控制台的输出,你直接想,读入utf-8的字符串,又输出到文本中,读的是什么,它还会输出什么。我感觉char 输出汉字比 wchar_t更容易理解。
http://topic.csdn.net/u/20120725/10/198656a0-6642-49f8-851d-dbec4a8aa8cd.html?seed=159402757&r=79225628#r_79225628

#14


十分感谢各位,最近事多事乱,竟然这么长时间没有结贴……
我最近会好好研究,整理以后,有什么问题再来问大家。

#15


引用 12 楼 zhao4zhong1 的回复:
wchar_t unicode[1]=L'汉';//0x49 0x6c ;Little endian unicode 0x6c49
//UTF-8 编码字符理论上可以最多到 6个字节长,但目前全世界的所
//有文字和符号种类加起来也只要编到 4个字节长就够了。
//  UTF-8 是以 8位(即 1个字节)为单元对原始码进行编码(注意一
//点:这里所讲的原始码都是指Unicode码),并规定:多字节码(2个字
//节以上才称为多字节)以转换后第1个字节起头的连续“1”的数目(这
//些连续“1”称为标记位),表示转换成几个字节:“110”连续两个
//“1”,表示转换结果为2个字节,“1110”表示3个字节,而“11110”
//则表示4个字节……跟随在标记位之后的“0”,其作用是分隔标记位和
//字符码位。第2~第4个字节的起头两个位固定设置为“10”,也作为标
//记,剩下的6个位才做为字符码位使用。
//  这样,2字节UTF-8码剩下11个字符码位,可用以转换0080~07FF的
//原始字符码,3字节剩下16个字符码位,可用以转换0800~FFFF的原始字
//符码,由此类推。编码方式的模板如下:
//
//原始码(16进制) UTF-8编码(二进制)
//--------------------------------------------
//0000 - 007F       0xxxxxxx
//0080 - 07FF       110xxxxx 10xxxxxx
//0800 - FFFF       1110xxxx 10xxxxxx 10xxxxxx
//……
//--------------------------------------------
//
//  模板中的“x”表示字符码。
//  VB能识别的 Ascii码<007F,所以在VB中,Ascii码都只能编为1个
//字节的UTF-8码。汉字的 Unicode编码范围为0800-FFFF,所以被编为
//3个字节的UTF-8码。
//  例如“汉”字的Unicode编码是6C49,6C49在0800-FFFF之间,所以
//要用3个字节的模板:1110xxxx 10xxxxxx 10xxxxxx。
//1110xxxx 10xxxxxx 10xxxxxx
//11100110 10110001 10001001 0xE6,0xB1,0x89
//    0110   110001   001001
//0110110001001001 0x6c49
char utf8[3]={0xE6,0xB1,0x89};//utf8 汉


赵老师,我找你找的好辛苦啊。。。您可否帮我看一个问题贴,急需您的解答。下面是我发的帖子的网址http://bbs.csdn.net/topics/390936735?page=1#post-398557764

#1


发错地方了?版主帮帮忙给转一下位置吧。傻掉了,发地方了。可能

#2


char型变量是用来存储Unicode编码的字符的,unicode编码字符集中包含了汉字,所以,char型变量中当然可以存储汉字啦。不过,如果某个特殊的汉字没有被包含在unicode编码字符集中,那么,这个char型变量中就不能存储这个特殊汉字。补充说明:unicode编码占用两个字节,所以,char类型的变量也是占用两个字节。 

刚刚看到上面这段,摘过来。很晕。我的项目 是C++,字符设置为unicode,那么char就是两个字节?!
char不是一个字节的吗?上面时候改了?

#3


该回复于2012-07-03 08:26:34被版主删除

#4


通知说有人回复了?我看不到……

#5


对电脑而言没有乱码,只有二进制字节;对人脑才有乱码。

推荐使用WinHex软件查看文件或内存中的原始字节内容。

VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)

提醒:
“学习用汇编语言写程序”

“VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
(Linux或Unix下可以在用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)”
不是一回事!

不要迷信书、考题、老师、回帖;
要迷信CPU、编译器、调试器、运行结果。
并请结合“盲人摸太阳”和“驾船出海时一定只带一个指南针。”加以理解。
任何理论、权威、传说、真理、标准、解释、想象、知识……都比不上摆在眼前的事实!

#6


char wchar_t这两个是数据类型,一个是宽字节,一个是窄字节,其本身存储的是0xXX 或 0xXXXX(并不包含解释,只说明这些内存中的东西要用字符型或宽字节字符型进行解释)
Unicode和utf-8是编码方式,是用来解释内存中字符型或宽字节字符型数据0xXX或0xXXXX是什么的是英文"XXOO"啊还是中文"酱油"啊的作用,不能把两者混为一谈

#7


坛子里明白的没几个人,你要是特别想了解可以加我QQ。

#8


引用 5 楼  的回复:
对电脑而言没有乱码,只有二进制字节;对人脑才有乱码。

推荐使用WinHex软件查看文件或内存中的原始字节内容。

VC调试(TC或BC用TD调试)时按Alt+8、Alt+6和Alt+5,打开汇编窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应内存和寄存器变化,这样过一遍不就啥都明白了吗。
对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后……

看来还挺麻烦的。我去看看。十分感谢

#9


引用 6 楼  的回复:
char wchar_t这两个是数据类型,一个是宽字节,一个是窄字节,其本身存储的是0xXX 或 0xXXXX(并不包含解释,只说明这些内存中的东西要用字符型或宽字节字符型进行解释)
Unicode和utf-8是编码方式,是用来解释内存中字符型或宽字节字符型数据0xXX或0xXXXX是什么的是英文"XXOO"啊还是中文"酱油"啊的作用,不能把两者混为一谈


你的想法和我的差不多。但是我不确定。你有什么确定的手段吗?
我感觉5楼的手段可行。

#10


首先,内存中的数据是单纯的二进制数据,当然你要用十六进制来表示它也可以
不管你用什么指针指向这段内存,数据就是数据,不会有任何改变
你是用char*也好,用int*也罢,甚至用string*都一样,它们都只是指针,类型+地址而已,和它们指向的那段内存的数据没有任何关系——当然在使用中一般是有关系的,否则就是写代码的人有问题了

其次,中文是什么?英文是什么?日文是什么?
全部都是符号,全部都是概念,落在纸面上全部都是图形
和二进制有关系?一丁点的关系都没有

那么,什么是字符集?
规定二进制数据和某种语言内的文字之间的对应关系,这就叫该种语言的字符集
最基本的是ASCII,规定数值48对应字符'0',诸如此类,但由于这种对应关系的历史局限性(发明它的人当时没兴趣考虑非英文语言),同样的二进制数据,在不同的字符集内就对应不同的文字
而规定一套对应关系,使得二进制数据能够对应很多语言的文字,这就叫Unicode

unicode和utf8等等格式,本质上是不同的对应关系
char*可以用来指向各种数据的内存,不是因为它们都是char字符数据,而是因为char的大小是1个字节,方便指针控制(如果你要用void*指向各种内存,概念上是更加正确了,你试试看怎么偏移指针)
wchar_t其实就是typedef的2字节short,也就是对应unicode的编码范围为2字节数据,用的就是这种数据类型的字节数而已
所以char*和wchar_t*指向同一段内存,有什么错?一点错误都没有,它们都只指向这一段二进制数据而已,区别就在于你使用这两种类型的指针来操作数据的时候,按照相应的类型来操作这段内存,仅此而已

还有什么问题吗?

#11


google半天,没有说char为啥能够支持中文。

——按你的说法,char可以“支持”任何类型的变量,因为它们都是以字节为基本单位的二进制数据
——不是char支持中文,而是char*可以指向一段存有二进制数据的内存,这段内存中的数据按照某种对应关系对应中文的文字集合,而你用来显示文字的显示模块也按照这种对应关系来转换二进制数据到文字相关属性(文字图形等)
——所以正确的说法是,你用来显示/处理文字的函数/模块,支持中文这个文字集合,以及你所选择的unicode这种对应关系

#12


wchar_t unicode[1]=L'汉';//0x49 0x6c ;Little endian unicode 0x6c49
//UTF-8 编码字符理论上可以最多到 6个字节长,但目前全世界的所
//有文字和符号种类加起来也只要编到 4个字节长就够了。
//  UTF-8 是以 8位(即 1个字节)为单元对原始码进行编码(注意一
//点:这里所讲的原始码都是指Unicode码),并规定:多字节码(2个字
//节以上才称为多字节)以转换后第1个字节起头的连续“1”的数目(这
//些连续“1”称为标记位),表示转换成几个字节:“110”连续两个
//“1”,表示转换结果为2个字节,“1110”表示3个字节,而“11110”
//则表示4个字节……跟随在标记位之后的“0”,其作用是分隔标记位和
//字符码位。第2~第4个字节的起头两个位固定设置为“10”,也作为标
//记,剩下的6个位才做为字符码位使用。
//  这样,2字节UTF-8码剩下11个字符码位,可用以转换0080~07FF的
//原始字符码,3字节剩下16个字符码位,可用以转换0800~FFFF的原始字
//符码,由此类推。编码方式的模板如下:
//
//原始码(16进制) UTF-8编码(二进制)
//--------------------------------------------
//0000 - 007F       0xxxxxxx
//0080 - 07FF       110xxxxx 10xxxxxx
//0800 - FFFF       1110xxxx 10xxxxxx 10xxxxxx
//……
//--------------------------------------------
//
//  模板中的“x”表示字符码。
//  VB能识别的 Ascii码<007F,所以在VB中,Ascii码都只能编为1个
//字节的UTF-8码。汉字的 Unicode编码范围为0800-FFFF,所以被编为
//3个字节的UTF-8码。
//  例如“汉”字的Unicode编码是6C49,6C49在0800-FFFF之间,所以
//要用3个字节的模板:1110xxxx 10xxxxxx 10xxxxxx。
//1110xxxx 10xxxxxx 10xxxxxx
//11100110 10110001 10001001 0xE6,0xB1,0x89
//    0110   110001   001001
//0110110001001001 0x6c49
char utf8[3]={0xE6,0xB1,0x89};//utf8 汉

#13


引用 11 楼  的回复:
google半天,没有说char为啥能够支持中文。

——按你的说法,char可以“支持”任何类型的变量,因为它们都是以字节为基本单位的二进制数据
——不是char支持中文,而是char*可以指向一段存有二进制数据的内存,这段内存中的数据按照某种对应关系对应中文的文字集合,而你用来显示文字的显示模块也按照这种对应关系来转换二进制数据到文字相关属性(文字图形等)
——所以正确的说法是,你用……

不是char支不支持中文的问题,char只是存储空间只有1个字节,中文至少要2个字节,必然存不下,char字符串中你用utf-8编码,输出出来的还是那些字符还是utf-8必然没问题。
你可以不去想控制台的输出,你直接想,读入utf-8的字符串,又输出到文本中,读的是什么,它还会输出什么。我感觉char 输出汉字比 wchar_t更容易理解。
http://topic.csdn.net/u/20120725/10/198656a0-6642-49f8-851d-dbec4a8aa8cd.html?seed=159402757&r=79225628#r_79225628

#14


十分感谢各位,最近事多事乱,竟然这么长时间没有结贴……
我最近会好好研究,整理以后,有什么问题再来问大家。

#15


引用 12 楼 zhao4zhong1 的回复:
wchar_t unicode[1]=L'汉';//0x49 0x6c ;Little endian unicode 0x6c49
//UTF-8 编码字符理论上可以最多到 6个字节长,但目前全世界的所
//有文字和符号种类加起来也只要编到 4个字节长就够了。
//  UTF-8 是以 8位(即 1个字节)为单元对原始码进行编码(注意一
//点:这里所讲的原始码都是指Unicode码),并规定:多字节码(2个字
//节以上才称为多字节)以转换后第1个字节起头的连续“1”的数目(这
//些连续“1”称为标记位),表示转换成几个字节:“110”连续两个
//“1”,表示转换结果为2个字节,“1110”表示3个字节,而“11110”
//则表示4个字节……跟随在标记位之后的“0”,其作用是分隔标记位和
//字符码位。第2~第4个字节的起头两个位固定设置为“10”,也作为标
//记,剩下的6个位才做为字符码位使用。
//  这样,2字节UTF-8码剩下11个字符码位,可用以转换0080~07FF的
//原始字符码,3字节剩下16个字符码位,可用以转换0800~FFFF的原始字
//符码,由此类推。编码方式的模板如下:
//
//原始码(16进制) UTF-8编码(二进制)
//--------------------------------------------
//0000 - 007F       0xxxxxxx
//0080 - 07FF       110xxxxx 10xxxxxx
//0800 - FFFF       1110xxxx 10xxxxxx 10xxxxxx
//……
//--------------------------------------------
//
//  模板中的“x”表示字符码。
//  VB能识别的 Ascii码<007F,所以在VB中,Ascii码都只能编为1个
//字节的UTF-8码。汉字的 Unicode编码范围为0800-FFFF,所以被编为
//3个字节的UTF-8码。
//  例如“汉”字的Unicode编码是6C49,6C49在0800-FFFF之间,所以
//要用3个字节的模板:1110xxxx 10xxxxxx 10xxxxxx。
//1110xxxx 10xxxxxx 10xxxxxx
//11100110 10110001 10001001 0xE6,0xB1,0x89
//    0110   110001   001001
//0110110001001001 0x6c49
char utf8[3]={0xE6,0xB1,0x89};//utf8 汉


赵老师,我找你找的好辛苦啊。。。您可否帮我看一个问题贴,急需您的解答。下面是我发的帖子的网址http://bbs.csdn.net/topics/390936735?page=1#post-398557764