###ASCⅡ码#程序员
在ASCⅡ码制定的过程当中,对于代码是六、七、8位争议不断,因为可靠性的缘由,舍弃了6位,而因为成本问题(上世纪60年代来讲,8位代价是很是昂贵的),选择了7位编码。因而最后代码共有26个小写字母,26个大写字母,10个数字,32个符号,33个控制码,一个空格码,共128个代码组成了ASCⅡ码,成为了全球标准。windows
在小型计算机发展时期,8位一字节的标准获得巩固,因而决定以一个字节来储存字符,也就是8位编码,这样就有了128个额外的字符来补充ASCⅡ。函数
###多字节字符集DBCS#编码
256字符的字符集难以知足如中文、日文、韩文以及世界各个国家的各类文字需求,因而产生了多字节字符集(DBCS)。DBCS前128个代码就是ASCⅡ码,而较高的128个中有些还跟随有第二个字节,这两个字节在一块儿表示一个单独的字符,如一个汉字。指针
DBCS的问题在于,有些字符是单个字节组成的,例如ASCⅡ码,有些字符是两个字节组成的,这致使了字符串的字符长度不能由字节数量决定,字符串的长度须要解析后才知道,每一个字节都要被检查是否是双字节的前导字节。code
###Unicode字符集#内存
很明显的是,DBCS是一种很笨的解决方法,也产生了不少问题。做为程序员,咱们知道,与其混合使用1字节和2字节代码的DBCS,倒不如用一种全都是2字节16位编码的字符集,这就是Unicode字符集。字符串
Unicode被认为是“宽字符”,每一个Unicode的字符是16位而不是8位,在多字节字符集里咱们仍处理8位字符,而在Unicode字符集里咱们再也不处理8位字符。最开始的128个Unicode字符(0x0000到0x007F)是ASCⅡ码,而以后的128个Unicode字符(0x0080到0x00ff)是ASCⅡ码的扩展码。希腊字母表从0x0370到0x03ff,汉语日语韩语从0x3000到0x9FFF代码。扩展
Unicode的优势是只有一个字符集,避免了二义性,而其缺点是内存占比是ASCⅡ的两倍。数据类型
如今再来看char和wchar_t:
char a = 'A'; //定义了一个被0x41初始化的一个字节存储空间 char *p = "hello!"; //windows是32位系统,指针p占用4个字节空间存储p的地址 //字符串hello!存储在指针p指向的内存地址及其后6个字节,共7字节 //包括'h''e''l''l''o''!''\0' int s = strlen(p); //s=6; 记住这里 wchar_t wa = 'A'; //定义了一个被0x0041初始化的两个字节存储空间 wchar_t *wp = L"hello!"; //L表明了是宽字节字符,这里,hello!包括最后的\0共占用了14个字节 int s = strlen(wp); //s=1; 由于strlen接受的是8位字符,它把h也就是0x0068 //分为了0x68和0x00(内存存储顺序是高位高地址,低位低地址) //当读完0x68后,strlen判断读到0x00也就是字符串结束符,就结束输出了
wchar_t用了2个字节来存储字符,因此大部分处理char类型的函数都不能正常工做了,可是咱们有代替的,好比strlen的宽字节版本wcslen。在strlen定义的位置,也就是STRING.H中,strlen的声明以下:
size_t __cdecl strlen(cosnt char*);
而wcslen声明在了WCHAR.H中:
size_t __cdecl wcslen(const wchar_t*);
因此求wp的长度应该写为:
int s = wcslen(wp); //求得s=6,即为wp中字符个数
几乎全部的字符函数都有宽字符版本,例如printf的宽字符版本为sprintf,这些都定义在了WCHAR.H中。
###关于TCHAR.H#
Unicode也有不少的缺点,好比空间的占用以及某些方面的不兼容等等,咱们但愿维护两个版本,一个用ASCⅡ码而另外一个用Unicode字符集,但并不但愿建立两套源代码文件,因此有了TCHAR.H头文件。TCHAR为须要字符或字符串做为参数的普通库函数(例如printf,strlen,sprintf,wcslen)提供了一系列的替代名称(例如_tprintf,_tcslen),这些名称是“通用”的,由于他们能够指Unicode和非Unicode版本函数。
因为TCHAR不是标准的一部分,因此定义的每一个函数和宏都有一个下划线前缀。
定义方式以下:
#ifdef UNICODE #define _tcslen wcslen #else #define _tcslen strlen
以此类推其余函数定。
THCAR.H也提供了一个TCHAR类型来解决两个字符数据类型的问题。若是UNICODE标识符被定义了,
typedef wchar_t TCHAR;
不然的话,TCHAR就是char
typedef char TCHAR;
关于宽字符字符串前缀L的解决办法以下,若是UNICODE被定义了
#define __T(x) L##x
预处理将L和宏参数拼接在一块儿,例如x是hello,则L##x就是L"hello"
若是UNICODE没有被定义,则__T宏就定义以下:
#define __T(x) x
而后
#define _T(x) __T(x) #define _TEXT(x) __T(x)
因此写字符串的时候只须要将字符串字面写在宏内就能够了
_TEXT("hello!");
这样若是UNICODE被定义了,字符串就解释为宽字符组成的,若是没有被定义,就解释为8位字符组成的。
###关于char16_t和char32_t
随着Unicode的发展,类型wchar_t已经不足以知足需求,好比在字符串编码时,若是有特定的符号和长度特征的类型将颇有帮助,而wchar_t的符号和长度不一样的C/C++库有不一样的规定。所以C++11新增长了char16_t和char32_t。
char16_t:无符号类型,长16位,char32_t无符号类型,长32位
前缀u和U分别指出字符字面值的类型为char16_t和char32_t。