在C++中有两种类型可以用于表示字符,char和wchar_t。

但是字符串格式的标准却有很多种,如ASCII,UTF8,UTF16,UTF32等等。字符串的格式和char/wchar_t 的关系是什么呢?

首先要理解Unicode和UTF-8的关系,可以参考我转帖的文章:http://www.cnblogs.com/whyandinside/archive/2012/02/05/2338841.html

额外还有几个问题需要解决:

1. UCS-2、UCS-4、BMP

UCS有两种格式:UCS-2和UCS-4。顾名思义,UCS-2就是用两个字节编码,UCS-4就是用4个字节(实际上只用了31位,最高位必须为0)编码。下面让我们做一些简单的数学游戏:

  UCS-2有2^16=65536个码位,UCS-4有2^31=2147483648个码位。

  UCS-4根据最高位为0的最高字节分成2^7=128个group。每个group再根据次高字节分为256个plane。每个plane根据第3个字节分为256行 (rows),每行包含256个cells。当然同一行的cells只是最后一个字节不同,其余都相同。

  group 0的plane 0被称作Basic Multilingual Plane, 即BMP。或者说UCS-4中,高两个字节为0的码位被称作BMP。

UCS-4的BMP去掉前面的两个零字节就得到了UCS-2。在UCS-2的两个字节前加上两个零字节,就得到了UCS-4的BMP。而目前的UCS-4规范中还没有任何字符被分配在BMP之外。

2. UTF-16是如何表示Unicode的?

在基本多語言平面內定義的符號((Basic Multilingual Plane, BMP),或稱第零平面(Plane 0)),使用2個字節表示,在此之外的字符(其他平面內的字符),則使用4個字節表示。由於第零平面內,從0XD800到0XDFFF之間的區段是沒有使用的,因此可以利用0XD800-0XDFFF之間的值來對輔助平面的字符進行編碼。 
其編碼方法是:

  1. 如果字符編碼U小於0x10000,也就是十進制的0到65535之內,則直接使用兩字節表示;
  2. 如果字符編碼U大於0x10000,由於UNICODE編碼範圍最大為0x10FFFF,從0x10000到0x10FFFF之間 共有0xFFFFF個編碼,也就是需要20個bit就可以標示這些編碼。用U'表示從0-0xFFFFF之間的值,將其前 10 bit作為高位和16 bit的數值0xD800進行 邏輯or 操作,將後10 bit作為低位和0xDC00做 邏輯or 操作,這樣組成的 4個byte就構成了U的編碼。

UTF-16可看成是UCS-2的父集。在沒有輔助平面字符Mapping of Unicode character planes(surrogate code points)前,UTF-16與UCS-2所指的是同一的意思。但當引入輔助平面字符後,就稱為UTF-16了。現在若有軟件聲稱自己支援UCS-2編碼,那其實是暗指它不能支援在UTF-16中超過2bytes的字集。對於小於0x10000的UCS碼,UTF-16編碼就等於UCS碼。

3. wchar_t是UTF-16吗?他们之间的关系是什么?

wchar_t在不同的平台上size是不一样的,MSVC它是2字节的;而在Linux上它就是4字节了。wchar_t在Windows可用于存储UTF-16的字符;而在Linux上往往用于存储UTF-32在字符。

比如:Windows上的函数MultiByteToWideChar是这样描述的:Maps a character string to a UTF-16 (wide character) string. The character string is not necessarily from a multibyte character set.

int MultiByteToWideChar( __in UINT CodePage, __in DWORD dwFlags, __in LPCSTR lpMultiByteStr, __in int cbMultiByte, __out LPWSTR lpWideCharStr, __in int cchWideChar );

Different compilers and platforms define wchar_t differently, because they use different Unicode encoding techniques. On Windows/Visual C++ for instance, wchar_t is a 16 bit type, suitable for UTF-16. On GCC/Linux for instance, wchar_t is a 32 bit type, suitable for UTF-32.

Depending on your requirements (speed, memory usage), you should pick an internal format that suits the platform. On Windows it might be UTF-16, and on Linux it might be UTF-32. That way you won't have to transcode strings all the time, just to make simple platform-defined operations on them (wcslen(), wcscmp(), etc).

For external formats (text files, etc), I tend to use UTF-8. The reason is that files are considerably smaller if they contain text in a western language. Another benefit is that you don't have to consider endianess in UTF-8, which makes the chance of errors (on your or some other's part) less likely.

4. SBCS、DBCS和MBCS 
SBCS、DBCS和MBCS分别是单字节字符集、双字节字符集和多字节字符集的缩写。SBCS、DBCS和MBCS的最大编码长度分别是1字节、两字节和大于两字节(例如4或5字节)。例如:代码页1252 (ANSI-拉丁文 I)是单字节字符集;代码页936 (ANSI/OEM-简体中文 GBK)是双字节字符集;代码页54936 (GB18030 简体中文)是多字节字符集。单字节字符集中的字符都用一个字节表示。显然,SBCS最多只能容纳256个字符。

双字节字符集的字符用一个或两个字节表示。那么我们从文本数据中读到一个字节时,怎么判断它是单字节字符,还是双字节字符的首字符?答案是通过字节所处范围来判断。例如:在GBK编码中,单字节字符的范围是0x00-0x80,双字节字符首字节的范围是0x81到0xFE。我们顺序读取字节数据,如果读到的字节在0x81到0xFE内,那么这个字节就是双字节字符的首字节。GBK定义双字节字符的尾字节范围是0x40到0x7E和0x80到0xFE。

GB18030是多字节字符集,它的字符可以用一个、两个或四个字节表示。这时我们又如何判断一个字节是属于单字节字符,双字节字符,还是四字节字符?GB18030与GBK是兼容的,它利用了GBK双字节字符尾字节的未使用码位。GB18030的四字节字符的第一字节的范围也是0x81到0xFE,第二字节的范围是0x30-0x39。通过第二字节所处范围就可以区分双字节字符和四字节字符。GB18030定义四字节字符的第三字节范围是0x81到0xFE,第四字节范围是0x30-0x39。

5. UTF-8 可以和ANSII兼容;而UTF-16和UTF-32不可以。

6. 字符串有两种存储方式:保存总长度和结束符。结束符是最常使用的,比如char字符串使用\0来判断字符串结尾;而wchar的字符串使用’\0\0’来判断字符串结尾。 保存总长度也是一种方式,在COM中BSTR就是这样使用的。

BSTR(Basic STRing)实际上是类Pascal字符串,在BSTR的前4个字节保存了字符串长度,所以BSTR内部可以包括\0,它也不是靠\0来判断字符串结尾的。BSTR在c/c++中的定义实际上是wchar_t*,但因为BSTR是依靠前4个字节来判断字符串长度的,所以它的分配和释放都不同于普通的字符串,需要通过::SysAllocString和::SysFreeString等函数来分配和释放。

参考:

1. http://blog.sina.com.cn/s/blog_4c860d7e0100hzzj.html

C++字符串之一(字符表示)的更多相关文章

  1. UTF-8编码的字符串拆分成单字、获取UTF-8字符串的字符个数的代码及原理

    一.字符编码简介 1. ASCII码 在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(by ...

  2. Python中的字符串与字符编码

    本节内容: 前言 相关概念 Python中的默认编码 Python2与Python3中对字符串的支持 字符编码转换 一.前言 Python中的字符编码是个老生常谈的话题,同行们都写过很多这方面的文章. ...

  3. Swift入门篇-字符串和字符

    今天主要是介绍一下字符串的用法 ,字符串的语法和object-c语法不太一样,但是思想是一样,就是写法不太一样.如果您对.net和java语法比较熟悉的话,那您几乎没有深压力.如果您对swift 基本 ...

  4. swift中文文档翻译之--字符串和字符

    字符串和字符 A string is an ordered collection of characters, such as "hello, world" or "al ...

  5. 【C#】字符串与字符数组

    字符串与字符数组的相互转换. 字符串转换成字符数组: string ss="abcdefg"; char[] cc=ss.ToCharArray();     字符数组转换成字符串 ...

  6. The Swift Programming Language-官方教程精译Swift(4)字符串和字符

    String 是一个有序的字符集合,例如 "hello, world", "albatross".Swift 字符串通过 String 类型来表示,也可以表示为 ...

  7. Swift语言指南(十)--字符串与字符

    原文:Swift语言指南(十)--字符串与字符 字符串是一段字符的有序集合,如"hellow,world"或"信天翁".Swift 中的字符串由 String ...

  8. Swift连接字符串和字符

    字符串和字符的值可以通过加法运算符 (+) 相加在一起并创建一个新的字符串值: let string1 = "hello" let string2 = " there&q ...

  9. 字符类型char、字符串与字符数组、字符数组与数据数组区别

    字符类型是以ASCII码值运算的:小写字母比相应的大写字母大32,其中A=65,a=97 Esc键 27(十进制).'\x1B'(十六进制).'\33'(八进制) 转义字符:\0 空字符     AS ...

  10. Swift 学习- 04 -- 字符串和字符

    // 字符串 和 字符 // 字符串 是有序的 Character (字符) 类型的值的集合,  通过 String 类型的集合 // swift 的 String 和 Character 类型提供了 ...

随机推荐

  1. 在Windows XP下手动安装Apache+MySQL+PHP环境 要点

    在整个wamp环境搭建中,本质的工作如下: 1,配置系统对php中dll文件能默认处于调用状态.在windos下,对dll文件系统默认处于调用状态的,有两种采用的方式.第一种是:把需要调用dll文件复 ...

  2. twisted 使用

    工欲善其事,必先利其器,我们先来进行 twisted 框架的安装,由于平时使用的都是 Windows 系统,那么下面我们就讲解下 Windows 下 twisted 框架的安装(1)下载 twiste ...

  3. Nginx 配置指令的执行顺序(十一)

    紧跟在 post-access 阶段之后的是 try-files 阶段.这个阶段专门用于实现标准配置指令 try_files 的功能,并不支持 Nginx 模块注册处理程序.由于 try_files  ...

  4. 新建Android项目的时候,选择SDK的区别

    选择新建一个Android项目时候,出现MiniMum Required SDK.Target SDK.Compile With.Theme,如下所示,分别是什么意思呢? MinMum Require ...

  5. NDEF-NFC数据交换格式

    为实现NFC标签.NFC设备以及NFC设备之间的交互通信,NFC论坛(NFC FROUM)定义了称为NFC数据交换格式(NDEF)的通用数据格式.NDEF是轻量级的紧凑的二进制格式,可带有URL,vC ...

  6. intro

    懒得自己折腾wordpress又很想写博客. 作为一名把自己当成programmer的data scientist,毅然选择了博客园. 这里我想内容就是平时学到/使用的各种心得,更新频率不定. 兴趣范 ...

  7. Node.js log1: ERR can not find module express

    1.win7下创建项目中提示输入的命令:cd project&&npm install    安装失败 输入上面提示的命令,预期结果:自动安装了依赖 ejs 和 express,失败提 ...

  8. 杭电oj1219 AC Me

    Tips:本题中,输入字符串之后,直接从头到尾处理一遍,调用函数判断是否是字母,不要自己写循环判断是否为字母,易超时! 不过本题中有一个疑问,自己最开始用C写的,一直是Time Limit Excee ...

  9. hdu 1754 I Hate It_线段树

    题意:略 思路:套hdu1166模版改改就行了,要注意的是,网上有的代码是错的,还贴出来... #include <iostream> #include<cstdio> #in ...

  10. HDU 1852 Beijing 2008 数论

    题目地址: http://acm.hdu.edu.cn/showproblem.php?pid=1852 这道题和HDU1452类似. 题意:给你一个n.k,让你求2008^n所有因子的和(包括1和本 ...