C++字符型专题

C++字符型专题

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

本文是对《C++语法详解》一书相关章节的增修版,本文更清楚更详细的讲解了字符的来龙去脉以及基本的底层原理

《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

有兴趣的读者可参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。


专业名词解释

实现:通常是指按某种标准或原理而做出来的应用程序,如C++实现是指的按C++标准而制作出来的应用程序,通常是指编译器,因此,若本文中出现“依实现而定”是指的“依实现C++标准的应用程序而定,通常是指依编译器而定”



2.3.1 字符及其编码的基础知识


一、计算机怎样处理字符

计算机只能处理二进制数字,那么怎样处理字符呢?可以想到的最简单的办法就是在字符和数字之间进行映射(编码),即,只需把字符想办法转换为二进制数字就行了,比如将字符“A”映射为10进制整数65,然后再将65直接映射为二进制数0100 0001,同理,可将“B”映射为66等,这样计算机就能处理字符A了,这里的“映射”在计算机中被称为“编码”,现在的计算机就是使用这种简单的思想处理字符的,只是其具体过程更复杂,至此,可能大家会产生出以下问题:

  • 为什么要进行两次编码,直接编码为二进制不是更省事吗?
    其实这很简单,第一次编码准确的说其实就是为每个字符编了一个号,这个编号可方便人们使用,编号通常是10进制或16进制数,这样在以后指定某个字符时,可以直接使用数字来指定这个字符,很明显,直接使用二进制更不方便,比如,对于ASCII字符集,可以方便的使用65表示字符“A”,显然,使用二进制数0100 0001更不方便。
  • 为什么要使用编号来指定字符,而不是直接指定字符呢?
    比如,字符“A”,为什么要用编号65呢,直接用“A”不是更方便?对于英文字母这些常见的字符,直接使用字符当然更方便,但对于不是经常使用或者难输入、难显示、不显示的字符(比如积分号、求和符号、零宽度空格、回车换行符等),那么使用编号就更方便了。
  • 一个二进制比特串,比如0100 0001,为什么不会被处理为整数65,而被处理为字符“A”呢?
    这与该比特串的类型有关,如果类型为整型,则计算机就会解释为整数65,若为字符型,就会解释为字符了,同理,若为浮点型,则会按浮点型的规则解释这个比特串。
二、计算机怎样显示字符

1、字符集
说简单一点就是各种字符的集合,通常字符集还包括与字符相对应的编号,比如ASCII字符集、Unicode字符集等。

2、字符是什么
字符在计算机中其实是以图形的形式显示出来的,因此,可将字符理解为一个“图形”,或是一个具有某种图形的“符号”

3、字形(glyph)
字形用于表示字符的外形,比如字母a可以以多种外形对其进行书写,再如中文字符中的每一笔画都是一个字形,如“才”,可认为是由“一”、“亅”、“ノ”三个字形组成,因此,可把字符进一步理解为由一个个的字形组成的图形(或符号)。注:glyph也翻译为图元,图像。

4、字体
字体是一个拥有相同设计风格(或样式)的字形及从字符到字形映射关系的集合,比如,宋体、楷体、华文新魏等都是字体。属于同一字体的字符,都具有相同的书写(或显示)风格或书写样式。

5、点阵字体、矢量字体
常常见到的点阵字体、矢量字体,其实是对字形的一种设计方法,点阵字体是以一个一个点的形式来设计字形的轮廓的,矢量字体是以数学函数的形式来描述字形的轮廓的,具体从略。

6、计算机显示一个字符的简略步骤
当计算机接收到一串二进制之后,首先判断其类型,若是字符型,则检测使用的是什么字符集,再根据该字符集的相关规则,将这个二进制串转换为相应的编号,再根据这个编号在字符集中查找到对应的字符,再根据当前系统所使用的字体将其显示出来,其过程如图1所示。在以上过程中,若未在字符集中找到相应的字符或没有找到相应的字体,则可能会被显示为乱码或者直接不显示任何符号。

在这里插入图片描述

三、字符编码
1、字符的第一次编码
  • 字符进行的第一次编码是将字符编码为与一个数值(比如一个整数)相对应,其实就是将每个字符都编了一个号,所以将这里的编码称为编号更准确。比如将字符A编码为十进制整数65,B编码为66等,通常把此步骤形成的“字符数字对”集合称为字符集,比如常用的ASCII字符集,就是将128个常用的字符编码为128个整数,另外,还有Unicode字符集,GB2312字符集等。
2、字符的第二次编码
  • 字符的第二次编码就是把第一次编码好的数值再编码为相应的二进制串,这样计算机就可以直接存储该二进制串了,这次编码通常会使用相应的算法把数值转换(即编码)为二进制串,注意,并不一定是直接编码为相应的二进制数的。比如ASCII码是直接编码为二进制的,如字符A的第一次编码65,就直接编码为0100 0001;但是对于Unicode字符集有3种不同的二次编码方案,分别是UTF-8,UTF-16和UTF-32,目前使用较多的是UTF-8编码,该编码不是直接编码的,如“汉”字的第一次编码为U+6C49 (110 1100 0100 10012),第二次编码为1110 0110 1011 0001 1000 10012 ,可见,第二次编码并不是把十六进制数6C49直接转换为二进制数的。
3、编码数值与字符一一对应问题
  • 通常情况下,字符集中的字符与第一次编码后的数值(即编号)是一一对应的,但由于某些原因,Unicode并不总是如此,但是,人们还是习惯性的认为他们是一一对应的,于是通常使用第一次编码后的数值来确定一个字符。
4、易混、常混合使用的概念------编码
  • 由于历史原因,“编码”一词经典被混用,通常把第一次编码、第二次编码、字符集都称为编码,比如ASCII字符集也常称为ASCII编码,再如Unicode的第二次编码算法UTF-8,也被称为UTF-8编码。
四、补充知识-----Unicode与ISO 10646
1、Unicode
  • Unicode又称为统一码、万国码、单一码,是一种试图容纳全球所有字符的编码方案。Unicode包括字符集、编码方案等,它为每种语言中的每个字符设定了统一且唯一的二进制编码,以满足跨语言、跨平台的要求。Unicode制定的内容非常多,有兴趣的读者可以参阅相关文章。
2、ISO 10646与通用字符集(Universal Character Set,UCS)
  • 历史上,除了Unicode在试图制定全球统一的通用字符集外,国际标准化组织 ( ISO )也在制定相应的标准,其中通用多八位编码字符集(Universal Multiple-Octet Coded Character Set ),简称通用字符集(Universal Character Set,UCS)就是由ISO制定的ISO 10646标准所定义的字符集,是与Unicode并行的标准。最初,ISO与Unicode各自开发各自的项目,后来,双方意识到世界不需要两个不兼容的字符集,于是,双方进行了整合,并使彼此制定的标准相互兼容,以使两者保持一致,直到现在,两个组织都存在,并且各自独立公布各自的标准,但二者基本是一致的,不过Unicode的知名度比UCS更大,应用也更广泛。
3、代码点 ( Code Point,简称码点 )
  • Unicode把第一次编码后的数值称为码点(或代码点),使用“U+十六进制数”的形式表示,如U+6C49。注:码点、码点值、代码点三者经常混用。本文对码点的定义仅是一种简单粗略的理解,详细精确的定义请参阅有关Unicode编码的文献。
4、UTF-8、UTF-16、UTF-32
  • Unicode在进行第二次编码时有3种不同的算法把码点转换为二进制,分别是UTF-8,UTF-16和UTF-32,这三种算法常被称为UTF-8编码、UTF-16编码、UTF-32编码,他们分别使用变长位、16或32位、32位编码。也就是说,同一个字符,使用不同的编码算法将得到不同的二进制数值,比如,“汉(U+6C49)”,若使用UTF-8编码,则第二次编码后的值为0xE6 B1 89,若使用UTF-16编码,则第二次编码后的值就是码点值0x6C49。
  • 需要注意的是,在Unicode中,任意一个码点都可以使用UTF-8、UTF-16、UTF-32三种算法将其分别编码为三个不同的二进制数值,具体使用哪一种编码算法,这需要视所使用的应用而定,通常,应用都可自行设置使用哪一种算法。
5、码点并不一定与字符一一对应
  • 在Unicode标准中,码点与字符并不一定总是一一对应的,在Unicode标准中,一个字符有可能有多个码点,也有可能由多个码点来表示一个字符(常见于组合字符)。比如U+51C9与U+F977都是同一个字符“凉”,这主要是为了兼容韩国字符集的标准。再如,以下字符
    在这里插入图片描述
    是由基本字符g(U+0067)和U+0308(这个字符称为组合字符)组合而成,虽然以上字符是由两个Unicode码点组成,但现实中,人们会认为这是一个字符。以上由两个码点组合而成的字符在Unicode中被称为“用户感知字符”。

2.3.2 C++字符


一、C++使用的字符集

1、C++使用的是什么字符集是一个很重要的问题,这关系到能否正确显示、处理字符以及字符处理的方式,若两个C++系统使用了不同的字符集,有可能会出现乱码的情形。

2、C++实现(通常指编译器)有4种类型的字符集:基本源字符集、基本执行字符集、扩展源字符集、扩展执行字符集。

  • 基本源字符集用来编写程序的源代码,包括大小写字母、数字、常用符号等;
  • 基本执行字符集用于处理程序执行期间的字符,如显示到屏幕上的字符,基本执行字符集比基本源字符集增加了一些字符,如退格字符、振铃字符等。
  • C++标准还允许实现提供扩展源字符集和扩展执行字符集。注,扩展是指的额外增加的,因此,扩展字符集是指的由实现额外提供的字符集。

3、 C++具体使用的是什么字符集,要依实现而定。通常情况下,C++实现使用的字符集是主机系统的编码,如IBM大型机使用EBCDIC编码,若使用的是windows10系统中文版,则C++实现(通常指编译器)有可能会使用GB18030编码,不过,最常用的字符集是ASCII字符集,本文若未作特殊说明,均表示使用的ASCII字符集。

4、注意:很多常用的字符集,如Unicode、ISO10646等都会把ASCII字符集作为其子集。

二、C++中的字符
1、在C++中的字符有如下几种书写方式:
  • 将常规字符使用单引号括起来,如 ‘a’,‘b’,‘3’等,此种表示法代表的是字符的数值编码(即,编号),这种表示方式的好处是不需要记住该字符的数值编码。单引号是C++表示字符的特定标志,这种由单引号括起来的字符是字符字面值,本文也将这种字符称为“C++字符”以与常规字符相区别,比如字符a应书写为’a’,若直接写成a通常会被认为是变量名a,再如,字符2应书写为’2’,若直接写成2,则会被认为是数字2(通常被认为是整型)

  • 直接使用数值编码,即使用整数,这种表示方法并不是在所有场合都能表示字符,需视类型而定,如

    char c = 65;		//C++使用char声明字符类型,详见后文 
    cout<< c <<endl;	//输出字符A 
    int a= 65; 
    cout<< a <<endl;	//输出整数65
    
  • 使用单引号括起来的转义序列,转义序列详见后文。比如

    cout<< '\x41' <<endl;		//输出字符A
    
  • 通用字符名(详见后文)。比如

    cout<< '\u0041' <<endl;		//输出字符A
    
  • 宽字符(详见后文),如

    wcout << L'A' << endl;		//输出字符A,注:宽字符需使用wcout输出
    

2、字符串是用双引号括起来的,由0个或多个字符组合成,与单引号类似,双引号是C++表示字符串的特殊标志,应把字符串与字符加以区别,比如”a”表示字符串a,而’a’表示字符a。

3、除转义序列、通用字符名等特殊情形外,在单引号中只能有一个字符,若单引号中有超过1个以上的字符C++未作规定,因此不建义使用。超过1个以上的字符应使用双引号,表示这是一个字符串。比如’ab’,应写成”ab”。

三、转义序列

1、很多字符我们无法从键盘直接输入,比如回车符、退格符等不可打印字符,还有一些字符在C++中有特殊的意义,这些字符也不能被直接显示,比如双引号、单引号等,若需要表示这些字符就需要用到转义序列,由转义序列表示的字符通常被称为转义字符

2、转义序列以“\”反斜杠符号开始,后面紧接数字或字符。应像使用常规字符一样使用转义序列,也就是说,需使用单引号把转议序列括起来才能表示这是一个C++字符,比如’\n’表示回车换行,而’\b’表示退格,’\x61’表示字符a,同理’\’表示符号\。

3、注意:转义字符仅仅只有一个字符,虽然他是由几部分组成的。比如’\n’,表示一个字符,而不是两个字符’\’和’n’的组合。

4、转义序列有如下几种格式:

  • 1)、符号转义序列:即反斜杠后使用字符形式的转义序列,如\b、\n等,表2.4为C++定义的符号转义序列

  • 2)、8进制格式为:

    \ooo				//其中ooo表示1~3个8进制数
    
  • 3)、16进制格式为:

    \xh或\xhh...		//表示以x开头,后跟一个或多个16进制数
    

在这里插入图片描述

5、有关转义序列的规则

  • 1)、8进制或16进制的数值代表的是所使用字符集里与该字符所对应的数值编码,以下示例是使用ASCII字符集所表示的转义字符

    \40 (空格)			\7 (响铃)			\141 (字符a)
    
  • 2)、8进制或16进制转义序列,其取值范围不应超过该字符类型的长度,否则有可能报错,默认情况下字符的类型为char,通常char的长度为8位,比如

    cout<< ' \433';			//超出范围,可能报错
    

    字符数值编码超过char长度时,应使用其他字符类型,C++使用特有的前缀来表示其他字符类型,详见后文

  • 3)、8进制格式转义序列,最多只使用3位数来构成转义字符,超过3位数时就表示转义字符结束,比如,

    cout << "\1413";			//输出a3,即141所对应的字符a和字符3
    
  • 4)、16进制格式转义序列需要使用到后面跟着的所有数字,如

    cout<<"\x6c49";			//可能会因数值超出范围而报错
    

    \x6c49表示十六进制数值6c49所对应的字符,由于大多数机器的char型只占据8位的长度,通常\x6c49所对应的字符的编码会占据2个字节或更多字节(注意,\x6c49的类型是char),因此超过了8位,所以,该示例可能会报错。通常,超过8位的十六进制字符应与表2.8中某个前缀作为开头的扩展字符集一起使用。

  • 5)、系统默认使用8进制格式的转义序列,书写时不必书写前缀符数字0,因此,需要注意的是,无法在“\”反斜杠后面使用十进制数。比如"\0141",表示两个字符,即相当于’\014’和’1’两个字符,再如 ’ \141’ 其后的数字141是8进制数,而非10进制数

  • 6)、16进制格式转义序列的前缀x不能省略,前缀0须省略。如

    cout<<'\x61';		//输出字符a
    cout<< '\0x61';		//不能输出字符a,相当于单引号中有多个字符的情形
    
四、通用字符名

1、通用字符名其格式为

	\uhhhh 
	\Uhhhhhhhh

其后是相应的16进制数,表示的是字符的ISO 10646码点,需要注意的是\u之后必须是4位数,\U之后必须是8位数。比如\u00E2、\u00F6、\U00006C49等,若系统不支持ISO 10646编码,则无法显示这些字符。注:ISO 10646是与Unicode同步的国际标准

2、若实现支持扩展字符集,则可在标识符或字符串中使用通用字符名,这样可表示一些特殊字符。可在标识符中使用通用字符名意味着可以把通用字符名用于变量名、函数名等处,比如,变量名中可以有法文的重元音、汉字等。注意:转义序列和C++字符不能用于标识符,比如

int aaa\u6C49cccc = 33;			//正确,\u6C49是Unicode码点为6C49的“汉”字
int aaa\x6C40dddd=44;			//错误,转义字符\x6C49不能用于标识符中
int aaa'\x6C40'eeee=55;			//错误,C++字符不能用于标识符中

3、在变量名中使用形如\u6c49的通用字符名没什么意义,但是如果实现的扩展源字符集支持包含的通用字符名,则可以允许从键盘输入该字符,这意味着可以在变量名中直接使用\u6c49对应的“汉”字作为变量名,比如

int aaa汉cccc = 33;		//若实现的扩展源字符集支持,则正确
五、宽字符

1、对于像ASCII码这样的字符集,在将其编码为计算机所存储的格式时(即第二次编码)只使用1个字节(8位)来存储就足够了,但对于汉字来讲,使用一个字节来存储显然是不行的,比如汉字的“汉”字,GB18030的编码为0xBABA ,很明显,即使直接存储该数值也至少需要2个字节,也就是说1字节(8位)长的char类型是无法存储汉字的。除了汉字的编码之外,各个国家都为各自的国家制定了自已的编码,这些编码有些是使用等长的字节来存储,有些使用的长度则是不等的。

2、当需要处理的字符无法用一个字节来表示时,C++有两种处理方式

  • 若C++实现的基本字符集是大型字符集,则编译器厂商可直接把char定义为16位或更长的长度。有关char长度的讲解,见后文
  • 若C++实现同时支持较小的基本字符集和较大的扩展字符集,则使用8位的char来表示基本字符集,使用另一种被称为wchar_t的类型 (宽字符类型) 来表示扩展字符集。
  • 从以上规则可见,C++能否处理以及怎样处理超过1字节的字符是因C++实现(编译器)而定的。

3、宽字符常量

  • 宽字符常量只需在常规字符的前面加上大写字母L即可(中间不能有空格),比如L’a’、L’\x65’;等。

4、宽字符应使用wcout进行输出,比如wcout<<L’a’<<endl;

5、多字节字符和宽字符简介

  • 多字节字符指的是存储字符长度(即第二次编码时二进制位的长度)为1到多个字节长度的字符,而宽字符一般指的是Unicode字符集中的字符。宽字符和多字节字符并没有严格的定义,理论上来讲,Unicode也是多字节字符,再如,汉字的GB2312编码也是多字节字符,除此之外,各国都可能制定有各自的多字节字符编码集。
六、指定字符常量的类型

通过添加前缀的方式可以改变字符的默认类型,如表XXX所示,其中char16_t、char32_t是C++11新增的类型,详见后文
在这里插入图片描述


2.3.3 C++的字符类型


一、C++中的字符类型

1、在C++中有char、wchar_t、char16_t和char32_t几种字符类型

2、char用于基本字符集,其他字符类型用于扩展字符集,wchar_ t用于确保可以存放机器最大扩展字符集中的任意一个字符,char16_t 和char32_t 则用于Unicode 字符集。

3、char:通常所说的字符类型就是指的char型,这是常规的、经常使用的字符类型。

4、wchar_t,即宽字符类型,其长度和符号是不确定的,随实现而异,通常情况下,宽字符一般占据2个字节的长度,使用的字符集是Unicode字符集。然而,在实际处理字符时,若使用特定长度和符号的类型,将会大有益处,为此,C++11新增了char16_t和char32_t两种类型。

5、char16_t是无符号的,长度为16位,其对应的常量使用前缀u表示。

6、char32_t是无符号的,长度为32位,其对应的常量使用前缀U表示

7、wchar_t、char16_t、char32_t都有各自的底层类型,通常是一种内置的整型,具体是哪种类型是因实现而异的,如wchar_t的底层类型可能是unsigned int,也可能是int

8、再提醒一下:C++11新增的char16_t和char32_t 的好处是,长度是固定的,这是与wchar_t不同的地方。

二、char的长度

1、char所占据的长度为能够表示目标计算机系统中的所有基本符号,也就是说,char的长度可能是8位、16位等长度,需视具体情况而定。通常情况下,使用8位就可以表示所有的基本符号了。

2、注意:虽然C++标准没有对1字节是多少位作出规定,但是char的长度始终被认为是“一个字节”,也就是说,若char的长度为16位,则在C++中,一个字节的长度就是16位,而不是8位。通常情况下,一个字节都是指的8位,本文未作特殊说明,一个字节都是指的8位。

3、char占据的位数可以使用climits头文件中的符号常量CHAR_BIT或根据其最大值UCHAR_MAX来判断。

三、char的符号

1、默认情况下C++没有规定char的符号,也就是说,默认情况下char既不是有符号的,也不是没有符号的,char的符号由实现决定,一般的编译器都把char当作signed来处理。可以使用unsigned和signed来明确指定char是否有符号,比如unsigned char表示无符号char。

2、注意:类型char和signed char是不一样的。也就是说,字符型可被理解为有三种:char、signed char、unsigned char,但表现形式却只有两种,即singed char或unsigned char之一, 具体是哪种由编译器决定。

3、C++并没有规定带符号类型应如何表示,但是约定了在表示范围内正值和负值的量应该平衡。因此,8比特的signed char 理论上应该可以表示-127 至127 区间内的值,但大多数现代计算机将实际的表示范围定为-128 至127

4、当把char当作整数来使用时,char的符号就很重要了,因为char类型占据一个字节(一般为8位),因此signed char表示范围是-128 ~ 127,unsigned char表示的范围是0 ~ 255。

5、判断编译器中char的类型是否是有符号char的方法:

  • 1)、方法一:使用头文件中的符号常量:若char是有符号类型,则CHAR_MIN(表示char类型的最小值)的值应与SCHAR_MIN的值相同,CHAR_MAX应与SCHAR_MAX的值相同;若char是无符号类型,则CHAR_MIN的值应为0,而CHAR_MAX的值应与UCHAR_MAX的值相同。
  • 2)、方法二:假设一个字节为8位,首先对char变量赋一个大于128小于255的数,然后将此变量赋给一个整型变量,再输出这个整型变量,若输出的值为原值则表示是无符号型char,若不是原型(有符号型会溢出,因此不可能输出原值),则表示是有符号型char;比如char c=222; int a=c; cout<<a<<endl; 若输出的a是原值222则表示char的类型是无符号型的,若输出的的不是原值则表示是有符号型的。注意:在有些编译器中char c=222;可能会出错(数据溢出),若在这种编译器下此语句出错就表示char的类型是有符号型。
四、字符与整数

1、C++将字符表示为整数,该整数是与其字符相对应的数值编码,这样就不必使用专门的转换函数在字符和ASCII码之间转换,这在一定程度上提供了方便。因此,在C++中通常把char当作比short更小的整型来使用,或把整型当作char来使用,这意味着

  • 可对char进行整数的相关操作,比如,进行加、减等运算,比如

    char c='a'+1;
    cout<<c<<endl;		//输出字符b
    
  • 可将整数赋值给char类型变量,同理也可以将char变量赋给int变量;比如

    char c=97; 
    cout<<c<<endl;		//输出字符a(数值97是ASCII字符集中的字符a的编码)
    int d=’a’; 
    cout<<d<<endl; 		//输出97,因为字符a的ASCII编码为97。
    

2、为什么cout会把char类型变量输出为字符而不是整数值呢?这是因为cout将需要输出的内容进行了相应的转换,这种转换工作是由变量的类型所引导的,也就是说,变量的类型将影响cout如何显示值,因此,cout在输出char时,将其相应的值转换为需要显示的字符,同理,cout在输出int型变量时,则将其值显示为一个整数值。比如

char c=97;
cout<<c;			//输出a,通过查看内存可以知道,变量c的值仍然是整数97

3、注意:在C++版本2.0以前,cout将字符变量显示为字符,将字符常量显示为数字,把字符常量存储为int类型,不过现在基本上都是2.0以后的版本,C++将字符常量存储为char类型,因此不用担心以上问题。比如

char c = 'a';		//在早期版本中,表示从常量'a'(int型)中复制8位到变量c中,此步会有精度损失
cout<< 'a' <<endl;	//早期版本输出整数值97,并不会输出字符a
cout<< c << endl;	//输出整数97,注:此例有待考证,因为第一步赋值过程可能有精度损失
五、透彻理解C++的字符及其类型
1、理解C++字符
  • 转义序列、通用字符名表示的是字符集中对应编号的一个字符,这里的字符其实不能称为真正意义上的C++字符,应将他们理解为一个符号或图形,比如,\x6c49、\u6c49、\U00006c49都表示字符集中编号为6c49的一个符号,只有给这个符号(或图形)加上单引号之后,才能表示一个C++字符,说简单一点,\x6c49、\u6c49类似于未加单引号的符号a,只有给符号a加上单引号之后才能被称为C++字符。比如,

    char a\u6c49c = '\u6c49'; 	//表示变量的名字由符号a、\u6c49、c组成
    

    怎样理解以上语句左侧的\u6c49与右侧的’\u6c49’呢?前文已讲过,通用字符名可以用于标识符。左侧表示的是变量名,变量名是对一段内存取的名字,代表的是内存(后文会详细讲解),而右侧带单引号的’\u6c49’代表的是一个C++字符,表示的是存储在内存中的数据,因此,以上语句表示的是,在一段名称为a\u6c49c的内存中存储数据’\u6c49’,存储的数据是使用的字符集中编号为6c49所对应的字符的二进制串。

2、理解C++字符的类型
  • 1)、C++字符、宽字符、使用转义序列、通用字符名表示的C++字符,这几种字符的区别在于他们的类型以及长度。注意,宽字符已经在C++字符前使用前缀L明确指定了其类型为宽字符类型了

  • 2)、C++字符默认的类型是char,也就是说,由单引号括起来的字符的类型是char,他的长度是1个字节。比如,‘a’、’\u0061’、’\x6c49’、’\u6c49’、’\U00006c49’的类型都是char,其长度为1字节,但是,’\x6c49’、’\u6c49’、’\U00006c49’在字符集中所对应的字符的长度明显不止1个字节,所以有可能产生错误(这种情形在不同编译器上的处理方式不相同),要表示这种超过1个字节的字符,就需要使用到wchar_t、char16_t、char32_t类型,比如

    L'\x6c49'		//宽字符类型,长度不确定,通常为2字节
    u'\u6c49'		//char16_t类型,长度为16位
    U'\U00006c49'	//char32_t类型,长度为32位
    u'a'			//char16_t类型,长度为16位
    U'\097'			//char32_t类型,长度为32位
    L'\u6c49'		//宽字符类型,长度不确定,通常为2字节
    

    以上方法虽然能正确表示对应的字符,但不一定能使用cout正确输出,因为,cout把输出看作char流。

  • 3)、示例

    char x = 'a';			//'a'被存在在1字节的内存单元中
    wchar_t x1 = 'a';		//'a'被存在在2字节的内存单元中(若wchar_t的长度为2字节)
    char16_t x2 = 'a';		//'a'被存在在16位的内存单元中
    char32_t x2 = 'a';		//'a'被存在在32位的内存单元中
    

    以上示例,虽然都是存储的同一个字符字面值’a’(该字符字面值的长度为1字节),但,由于各变量的类型不同,该字符在内存中所占的长度是不一样的。


作者:黄邦勇帅(原名:黄勇) 2021年5月6日



在这里插入图片描述


评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值