宽与窄、定长与变长字符编码方式

数据类型

在C++的数据类型表示中,通常char为1个字节,int为4个字节,double为8个字节。

编码方式

编码方式英文字符占用字节数中文字符占用字节数
GBK12
GB231212
GB1803012
ISO-8859-111
UTF-813
UTF-1644
UTF-16BE22
UTF-16LE22

ASCII编码

ASCII码使用指定的7位或8位二进制数组合来表示128或256种可能的字符。
0~31及127(共33个)是控制字符或通信专用字符,其余为可显示字符。

GBK编码进化(DBCS)

GB-2312

连续2个扩展ASCII码的扩展区域(0xA0以后)来表示一个汉字。

日文、韩文、阿拉伯文、台湾繁体都使用类似的方法扩展了本地字符集的定义,现在统一称为MBCS字符集(多字节字符集)。
各个国家的定义的字符集有交集,因此使用GB2312的软件,就不能在BIG-5的环境下运行(显示乱码)。

GBK

第一个字节是大于127,就固定表示这是一个汉字的开始,不管后面跟的是不是扩展字符集里的内容。
扩展后包括了GB2312的所有内容,同时新增了近20000个新的汉字(包括繁体字)和符号。

GB18030

Unicode字符集 与 UTF-8编码

Unicode只是字符集,它只规定了每个符号的二进制值,但是符号具体如何存储它并没有规定。UTF-8等才是字符编码规则。

UTF-8

utf-8是Unicode最重要的实现方式之一,是一种变长的编码方式。

  • 如果一个符号只占一个字节,那么这个8位字节的第一位就为0(0xxxxxx);
  • 如果为两个字节,那么第一个字节的前两位都为1,然后第一个字节的第三位为0,第二个字节的前两位为10(110xxxxx 10xxxxxx);
  • 如果是三个字节的话,那么第一个字节的前三位为111,第四位为0,剩余的两个字节的前两位都为10(1110xxxx 10xxxxxx 10xxxxxx)。
  • unicode的字符编码和utf-8的存储编码表示是不同的。例如"严"字的Unicode码是4E25,UTF-8编码是E4B8A5。UTF-8编码不仅考虑了编码,还考虑了存储。4E25的二进制位 0100,1110,0010,0101。utf8的中文汉字一般是3个字节(1110xxxx 10xxxxxx 10xxxxxx),组合起来为 1110,0100,1011,1000,1010,0101 =E4B8A5。

字符集之在UTF-8中,一个汉字为什么需要三个字节?
这次彻底搞懂Unicode编码和UTF-8、UTF-16和UTF-32
utf-8中一个汉字是3个字节,你知道吗?

其它

ANSI编码

Windows操作系统上的别称。具体编码方式与操作系统有关:在中文简体Windows操作系统上,ANSI就是GBK;在泰语操作系统上,ANSI就是TIS-620(一种泰语编码);在韩语操作系统上,ANSI就是EUC-KR(一种韩语编码)。

Latin1编码(又名ISO-8859-1编码)

Latin1也是单字节编码方式,也就是说最多只能表示256个字母或符号,并且前128个和ASCII完全吻合。后面那128个值,赋予他们一些泰语、希腊语等字母或符号。

Latin1是Mysql数据库表的默认编码方式。单字节编码的一大好处:显示可以乱码,但是里面的数据值不会丢失。

  • 把UTF8编码的“讯”字(UTF8编码为0xE8AEAF,占三个字节)存入了Latin1编码的Mysql表,那么在Mysql眼里,你存入的并不是一个“讯”字,而是三个Latin1的字母(0xE8,0xAE,0xAF)。需要注意读取出来该值的时候,自己要以UTF8编码的方式显示出来,要不然就是乱码。=》通常的解决方案,建表的时候就声明charset为utf8。

01-程序员必备:彻底弄懂常见的7种中文字符编码

宽、窄字符类型

窄字符

常用的字符类型是 char,长度为 1,只能容纳 ASCII 码表中的字符。

窄字符串

对于 char 类型的窄字符串,c 语言并没有规定使用哪种特定的编码。

puts("百度一下");    //不能使用ASCII编码,具体编码方式不同编译器不同

代码文件存储

一般使用 UTF-8(大部分字符串可以用一个字节保存):兼容 ASCII,同时基于 Unicode,能支持全世界的字符。
windows 记事本默认使用本地编码 ANSI,与操作系统有关。

宽字符

类型:UTF-16、UTF-32,均基于 Unicode 字符集。
UNICODE的用处就是定长表示世界文字,据统计,用两个字节可以编码现存的所有文字而没有二义

PS:Unicode字符集一般是指UTF-16编码的Unicode,但Unicode字符集不等于每个字符占两个字符。

主流编辑器【中文】处理方案

  • 微软编译器(内嵌于 Visual Studio 或 Visual C++ 中)采用 UTF-16 编码,使用 2 个字节存储一个字符,用 unsigned short 类型就可以容纳。
  • GCC、LLVM/Clang(内嵌于 Xcode)采用 UTF-32 编码,使用 4 个字节存储,用 unsigned int 就可以容纳。

宽字符类型 wchar_t

在微软编译器下,wchar_t长度是 2,等价于 unsigned short。
在 GCC、LLVM/CLang 下,wchar_t长度是 4,等价于 unsigned int。

在Windows上,wchar_t通常是16位的,而在Linux上,wchar_t可能是32位的。

L 前缀

将ANSI字符串转换成unicode的字符串,就是每个字符占用两个字节。

#include <wchar.h>
#include <locale.h>

wchar_t a = L'A';  //英文字符(基本拉丁字符)
wchar_t b = L'9';  //英文数字(阿拉伯数字)
wchar_t c = L'中';  //中文汉字
wchar_t* d = L"Hello World!你好,世界!"; //每个字符都是宽字符

//将本地环境设置为简体中文
setlocale(LC_ALL, "zh_CN");

//使用专门的 putwchar 输出宽字符
putwchar(a);  
putwchar(b);  
putwchar(c);

//使用通用的 wprintf 输出宽字符, _格式控制"%lc"_
wprintf(
    L"Wide chars: %lc %lc %lc\n",  //必须使用宽字符串
    a, b, c
);

//使用通用的 wprintf 输出宽字符串,格式控制"%ls"_
wprintf(L"d: %ls \n", d);

兼容两种字符集

使用 _TTCHAR 等实现程序对多字节字符集及宽字节字符集的兼容。

多字节字符集宽字节(UNICODE)字符集通用
charwchar_tTCHAR
char*wchar_t*TCHAR*
LPSTRLPWSTRLPTSTR
LPCSTRLPCWSTRLPCTSTR
类型含义
WCHARUnicode character (wchar_t)
TCHARMBCS or Unicode character
LPSTRstring of char (char*)
LPCSTRconst string of char (const char*)
LPWSTRstring of WCHAR (WCHAR*)
LPCWSTRconst ant string of WCHAR (const WCHAR*)
LPTSTRstring of TCHAR (TCHAR*)
LPCTSTRconst ant string of TCHAR (const TCHAR*)
TCHAR* t = _T("");

TCHAR curError[1024];
sprintf(curError, _T("lTagG:%04x,lTagE:%04x,value:%s\r\n"), lTagG,lTagE,szValue);

_T()、_TEXT()、TEXT()

L"字符串" :用于告诉编译器该字符串应该作为Unicode字符串来编译。当编译器将字符串置于程序的数据部分中时,它在每个字符之间分散插入零字节。=》只有当定义了_UNICODE时,程序才能成功地进行编译。

使用_T()_TEXT()TEXT()改写,无论是否定义了_UNICODE宏,它都能够正确地进行编译。根据你的环境设置,使得编译器会根据编译目标环境选择合适的(Unicode还是ANSI)字符处理方式。

TCHAR *sz = _TEXT("Helloworld");

如果定义了_UNICODE,那么_TEXT定义为下面的形式:
#define _TEXT(x) L ## x
如果没有定义_UNICODE,_TEXT将定义为:
#define _TEXT(x) x

#ifdef UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif
 #ifdef UNICODE
 #define _T(x) L##X
 #else
 #define _T(x)x
 #endif

TEXT()使用时需要在#include<WinNT.h>前加上#include <Windows.h>才能使用TEXT,TEXT是根据UNICODE来确定宏的。如果只#include<WinNT.h>编译器是会报错的。

编译器配置

_UNICODE宏

只要在程序中有_UNICODE宏的,那么就是使用的【宽字符】,否则使用【单字节字符】。

_MBCS宏

多字节字符集(multi-bytecharacter set or MBCS)

单字节字符集(singlebyte character set or SBCS)

ASCII

编码字符集 VS 运行字符集

编码字符集:源文件使用的字符集。一般使用 UTF-8,以尽量节省存储空间,方便跨国交流。

运行字符集:程序中的字符或者字符串使用的字符集。也就是程序运行后使用的字符集。一般使用 UTF-16、UTF-32 编码,能够快速定位(查找)字符,提高处理速度。

Win32API

Win32中的每个与字符串相关的API和message都有两个版本,例如:SetWindowTextA()、SetWindowTextW()。后缀A表明这是MBCS函数,后缀W表示这是Unicode版本的函数。

全角 VS 半角

在字符集中,全角和半角字符对应的编号(或者说编码值)不同,是两个完全不一样的字符。ASCII 码只定义了半角字符,没有定义全角字符。

visual c++中_T、_TEXT和TEXT宏的区别和作用
C 语言学习(十二)C 语言中的字符(宽字符与窄字符)、从字符谈谈 C 语言的编码、转义字符-CSDN 博客
_T、_TEXT、L、TEXT之间的区别

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值