关于字符集,编码格式,大小端的简单总结

只要你和计算机打交道,这些问题可以说是天天会遇到,但是很多人是似懂非懂, 能真正完全理解的人却不多, 下面是个人的一些理解,有错欢迎指正.

最早的计算机只支持ASCII码, 具体来说就是用1个字节(最高位为0, 没有用)表示0到127,总共128个字符, 这样就可以完全满足英语应用的要求了。

后来扩展到欧洲语系,理论上一个字节可以表示256个字符, 欧洲人就把剩余的128个字符(最高位为1)按照自己语言(法语,德语...)的要求扩充应用了起来, 好像也能满足需要。

然后又到了亚洲国家,比如中国,中文汉字有十多万,这剩余的128个字符根本不够我用啊, 怎么办? 于是就有了两个字节的编码,如中文的GBK, GB2312, BIG5等,当然日语,韩语等其他亚洲国家也有自己编码方式。

这就是所谓的多字节编码(MBCS)方式, Win95/98时代只支持这种方式, 那时候处理字符串非常痛苦, 因为它里面有些字符是一个字节表示的,也有一些是多个字节表示的, 比如字符串"你好abc", 里面明明是5个字符,strlen返回长度却是7, 你要正确识别字符个数,可以使用类似_mbslen的API, 但是实际上该API内部会绑定当前的字符集, 不然神仙也识别不了。

要统一解决上面的问题, 需要有一个世界通用的统一编码格式, 那就是UNICODE。

UNICODE个人感觉分广义和狭义, 广义的UNICODE包括UTF8, UCS2, UCS4, 而狭义的UNICODE(主要是Windows平台)就是指UCS2。

先说UCS2, Windows平台上常说的UNICODE实际上就是指UCS2, 简单来说就是统一用2个字节的编码,表示实际上所有语言的常用字符。

再说UTF8, 有了上面的UCS2,为甚么还有要UTF8? UCS2把任何字符全都编码成2个字节(包括我们常用的英文字符), 这样极大地增加了网络传输和数据存储的开销,于是就有了UTF8。UTF8对英文字符还是1个字节存储,只对其他语言字符用多个字节存储(2-6个字节)。UTF8和UNICODE可以完全对应的相互转换, 具体可以参考这里

为什么还要有 UCS4? UCS2用2个字节,最多也只能表示0xFFFF+1 = 65536个字符, 但是我们仅汉字就有十多万,所以UCS2/UTF8收录的也只是我们一些常用的汉字, 所以我们需要UCS4, 用4个自己表示一个字符,可以表示0xFFFFFFFF+1=4294967296个字符, 它才是我们以后的终极解决方案。

在Windows上不同编码方式的相互转换可以通过WideCharToMultiByteMutiByteToWideChar进行, 它里面WideChar就是指UCS2, 可以看到它这里把UTF8也命名成MultiByte, 是不是有点误导...

下面再谈小大小端(little-endian, big-endian).

计算机是以字节为寻址单位的,这就涉及到字(2个字节), 双字(4个字节)及其他多字节单位 在计算机内如何排布的问题, 这里无非就是2种:低字节在低地址的little-endian和高字节在低地址的big-endian.

如何区分当前系统是哪种类型的大小端? 曾经看到有经验的程序员也以当前的操作系统类型来判断, 实际上系统的大小端和你的CPU架构体系相关联, 比如说X86是小端, PowPC是大端,ARM则是可控制(默认也是小端)。

要判断当前环境是大小端实际上很简单: bool IsLittleEndian()  {  int i=1;  return (*(char *)&i == 1); }

曾经看到公司跨平台的代码没有通过大小端转换,直接通过memcpy某个表示长度的int在客户端之间传送,却没有发生问题, 感觉很奇怪, 最后发现原来当前公司的所有客户端(Win, Mac, ios, Android,Black,Berry,Linux)全都是小端。感觉现在大端的应用主要是网络字节序, Java内部全都是大端, PowPC等。

上面的UCS2和UCS4因为都是用多字节表示一个字符, 所以实际上都有大小端的问题,比如分别对应UNICODE-LE和UNICODE-BE, UTF8则没有大小端的问题。

下面再说一下BOM (Byte Order Mark), 上面说了各种编码方式以及大小端的问题, 那么我们怎么知道某个文本或者数据流是何种编码方式?

一般来说有3种方法:一种是分本显示指定, 比如web里html头一般会有这么一段"content="text/html;charset=utf-8"; 要不就是大家默认约定,比如自定义的网络数据流内的字符串一般都会用UTF8编码; 还有一种就是用BOM,通过在文件头里填入BOM规定的字节,从而区分文件是何种编码类型:

UTF-8 0xEF 0xBB 0xBF
UTF-16 BE 0xFE 0xFF
UTF-16 LE 0xFF 0xFE
UTF-32 BE 0x00 0x00 0xFE 0xFF
UTF-32 LE 0xFF 0xFE 0x00 0x00

有兴趣的同学可以用notepad保存,试下各种效果, 然后用UltraEdit的16进制方式查看验证。

最后讨论下C++编程中常见的关于字符编码方式相关的问题。

在C++编程中, 我们常打交道的无非是编辑器和编译器, 对编辑器起来说,我们常遇到就是乱码问题, 比如中文注释显示或是保存不了等, 解决办法就是把你的文件保存成Unicode(UTF8)。

对于编译器来说, 编码方式取决于它对C++标准的支持程度, 比如C++ 11以前,我们只能指定成2种:一种是MBCS,如char* p="abc哈哈"; 还有一种是UCS2, 比如wchar_t*p = L"abc哈哈", 这样编译器就知道你要表示的字符串类型。C++11之后,标准增加了UTF8和UCS4的支持, 比如char* p=u8"abc哈哈"表示UTF8, char32_t* p=U"abc哈哈"表示UCS4。

另外C++11还增加了UTF8, UCS2, UCS4相互转码的支持:

std::codecvt_utf8 封装了UTF-8与UCS2及UTF-8与UCS4的编码转换
std::codecvt_utf16 封装了UTF-16与UCS2及UTF-16与UCS4的编码转换
std::codecvt_utf8_utf16 封装了UTF-8与UTF-16的编码转换

对于C++跨平台开发, 我们经常遇到的就是默认用那种编码方式的问题,我们会发现Windows 的UCS2解决方案对其他平台来说是个异类, 一般来说有2种解决方法:

一种是统一用UTF8 , 但是这样对Windows来说有点麻烦, 因为Windows的API都是UCS2的,所以这种方式意味着任何字符串在传给Windows API 之前都要从UTF8转成UCS2; 还有一种就是用#define宏了, Windows上将字符串宏全都定义成UCS2, 其他平台则全都定义成UTF8。

一直很好奇,谁知道Windows为什么不用UTF8,非要搞得和其他平台不一样?

时间: 2024-10-06 19:32:06

关于字符集,编码格式,大小端的简单总结的相关文章

最简单的方式教你理解大小端字节序

学过编程的人都应该知道大小端字节序的概念,但是很多时候,总是把他们弄混,这是整理出来的一份很简单的方式理解字节序的文章,废话不多说,这里直接入正题. 什么是字节序? 字节序,简单来说,就是指的超过一个字节的数据类型在内存中存储的顺序 那么就很明显了,像char这样的类型,肯定不存在字节序的问题了. 字节序分为哪几类? 大端字节序: 高位字节数据存放在低地址处,低位数据存放在高地址处: 小段字节序: 高位字节数据存放在高地址处,低位数据存放在低地址处: 网络字节序: TCP/IP协议传输数据时,字

C语言怎么简单测试为大小端模式

1.什么是大小端模式? 大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放:这和我们的阅读习惯一致. 小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低. 2.知道大小端有何用? 首先要介绍一下字节序列,所谓的字节序列就是大于或者等于两个字节类型的数据存放在

大小端模式详解

http://www.cnblogs.com/xinsheng/archive/2012/04/18/2455039.html 端模式(Endian)的这个词出自Jonathan Swift书写的<格列佛游记>.这本书根据将鸡蛋敲开的方法不同将所有的人分为两类,从圆头开始将鸡蛋敲开的人被归为Big Endian,从尖头开始将鸡蛋敲开的人被归为Littile Endian(这句话最为形象).小 人国的内战就源于吃鸡蛋时是究竟从大头(Big-Endian)敲开还是从小头(Little-Endian

请讲普通话——一场关于异构平台通信的风波(粘包&#183;大小端方式&#183;网络字节序)

一.引子 前段时间用StriveEngine做一个信息采集系统,服务器是Windows的,客户端是各种单片机,以及Unix等等平台.这些异构的平台,被我召集起来“加强对话, 扩大共识, 深化合作”.都说有人的地方就有江湖,讲真,机器世界也一样!这些异构的平台,平日里各自为政,井水不犯河水,倒也相安无事.如今群雄会盟,共商大计,如我所料,势必会上演一波真正的血雨腥风! 就像新闻联播里常说的,“加强对话, 扩大共识, 深化合作”,首先得“加强对话”吧. 看着各位爷陆续到场,我稍稍清了清嗓子,不揣冒昧

C语言学习笔记(三) 使用union检查系统大小端模式

问题:请写一个C函数,若处理器Big_endian的,则返回0:若是Little_endian的,则返回1. 简单复习下大小端的概念: 大端模式(Big_endian):字数据的高字节存储在低地址中,而字数据的低字节则存放在高地址中. 小端模式(Little_endian):字数据的高字节存储在高地址中,而字数据的低字节则存放在低地址中. 提示:C语言中的char占1个字节,而int占4字节,因此如果某个int变量被赋值为1,则大端模式内存布局(由低到高,下同)应该为0x00,0x00,0x00

【C语言】大小端的判断

在文章的开头我首先要介绍一下大小端的概念: 大端模式: 是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿类似于把数据当作字符串顺序处理:地址由小向大增加,而数据从高位往低位放: 小端模式: 是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低,和我们的逻辑方法一致. 若将00000001放入计算机中就有两种方法: ----------------

Linux程序设计学习笔记----网络编程之网络数据包拆封包与字节顺序大小端

网络数据包的封包与拆包 过程如下: 将数据从一台计算机通过一定的路径发送到另一台计算机.应用层数据通过协议栈发到网络上时,每层协议都要加上一个数据首部(header),称为封装(Encapsulation),如下图所示: 不同的协议层对数据包有不同的称谓,在传输层叫做段(segment),在网络层叫做数据包(packet),在链路层叫做帧(frame).数据封装成帧后发到传输介质上,到达目的主机后每层协议再剥掉相应的首部,最后将应用层数据交给应用程序处理. 上图对应两台计算机在同一网段中的情况,

一场关于异构平台通信的风波(粘包&#183;大小端方式&#183;网络字节序)

一.引子 前段时间用StriveEngine做一个信息采集系统,服务器是Windows的,客户端是各种单片机,以及Unix等等平台.这些异构的平台,被我召集起来“加强对话, 扩大共识, 深化合作”.都说有人的地方就有江湖,讲真,机器世界也一样!这些异构的平台,平日里各自为政,井水不犯河水,倒也相安无事.如今群雄会盟,共商大计,如我所料,势必会上演一波真正的血雨腥风! 就像新闻联播里常说的,“加强对话, 扩大共识, 深化合作”,首先得“加强对话”吧. 看着各位爷陆续到场,我稍稍清了清嗓子,不揣冒昧

一起talk C栗子吧(第一百五十二回:C语言实例--计算机中的大小端)

各位看官们,大家好,上一回中咱们说的是socket通信地址的例子,这一回咱们说的例子是:计算机中的大小端 .闲话休提,言归正转.让我们一起talk C栗子吧! 大小端据说来源于小说<格列佛游记>,书中说:人们在争论打开鸡蛋的方式是从鸡蛋的大端还是小端打开鸡蛋.争论不休,甚至还引起了战争.你说说,不管你从哪一端打开鸡蛋,打开的都是鸡蛋呀,这有什么可以争论的呢?还要通过战争来解决.大家不必关注这个争论,如果真想了解其中的细节,可以看看这部小说.不过在计算机中的大小端就不像小说中争论打开鸡蛋那么简单