新增数据类型(C++11~C++20)

整数类型long long(C++11引入)

        整数long long是C++11才新加入标准的,用来表示一个至少为64位的整数类型。其对应的无符号类型的unsigned long long。C++标准还为其定义LL和ULL字面值后缀。

/*和其他整型一样,long long也能用于枚举类型和位域。如下的enum是由某种整数类型表示的,默认是int。
可以在名字后面使用冒号确定enum使用的类型*/
enum longlong_emun : long long {
    x1,
    x2,
};

struct longlong_struct {
    long long x1 ; 8;
    long long x2 : 24;
    long long x3 : 32;
};

std::cout << sizeof(longlong_enum::x1) << std::endl;    //输出大小为8
std::cout << sizeof(longlong_struct) << std::endl;    //输出大小为8

        和其他类型一样,C++为它加入整型的大小限制。在头文件中增加了LLONG_MAX、LLONG_NIM、ULLONG_MAX分别代表long long的最大值和最小值,以及unsigned long long的最大值。另外C++标准中对标准库头文件做了扩展,特化了long long和unsigned long long版本的numeric_limits类模板。这使得在程序中可以便捷地获取这些类型地最大值和最小值(在程序中应尽量少使用宏,用模板取而代之是明智选择)。

#include 
#include 
#include 

int main(int argc ,int argv)
{
    //使用宏方法
    std::cout << "LLONG_MAX" << LLONG_MAX << endl;
    std::cout << "LLONG_MIN" << LLONG_MIN << endl;
    std::cout << "ULLONG_MAX" << ULLONG_MAX << endl; 

    //使用类模板方法
    std::cout << "std::numeric_limits::max()" = 
        std::numeric_limits::max() << std::endl; 
    std::cout << "std::numeric_limits::min()" = 
        std::numeric_limits::min() << std::endl; 
    std::cout << "std::numeric_limits::max()" = 
        std::numeric_limits::max() << std::endl; 
}

新字符类型char16_t和char32_t(C++11引入)

        这二个是C++11标准开始引入的,它们分别用来对应Unicode字符集的UTF-16和UTF-32两种编码方式(编码方式是利用数字和字符集建立对应关系的一套方法,每种字符集都有各自的编码方法,例如Unicode字符集自己的编码方法有UTF-8和UTF-16和UTF-32这3种,现代计算机世界逐渐达成了一致,就是尽量以Unicode作为字符集标准。在Linux系统中可以通过使用 echo $LANG或直接输入local命令来查看字符集,也可以修改,比如 export LANG=zh_CN.UTF-8)。

        这里需要注意一点在C++98标准中提供了一个wchar_t字符类型,并且还提供了前缀L,用它来表示一个宽字符。那为什么还要引入新的字符类型呢?这是因为起初在定义wchar_t的时候并没有规定其占用内存的大小,以至于在Windows系统上wchar_t被实现为一个16位长度的类型,而在Linux和macOS上wchar_t却是32位的。这就导致了我们写的代码无法在不同平台上保持相同的行为。而char16_t和char32_t的出现解决了这个问题,它们明确规定了其所占用内存空间的大小,让代码在任何平台上都能有一致的表现。

Unicode编码方式

        UTF-32是最简单的编码方式,该方法使用一个32位大小的内存空间存储一个字符编码,由于Unicode字符集的最大个数为0x10FFFF(IOS 10646) ,因此4字节(0xFFFFFFFF)长度完全能够表示所有该字符集成员。虽然有点很多,但每个字符都用UTF-32的话太占用内存。

        UTF编码方法所需内存空间为2字节,由于内存空间的缩小,因此UTF-16最多支持0xFFFF个字符,这显然不够,于是UTF-16采用了一种特殊的方法来表达无法表示的字符。简单来说,从0x0000~0xD7FF以及0xE000~0xFFFF直接映射到Unicode字符集,而剩下的0xD800~0xDFFF用于映射0x10000~0x10FFFF的Unicode字符集,映射方法为:字符编码减去0x10000后剩下的20bit位分为高位和低位,高10位的映射范围为0xD800~0xDBFF, 低10位的映射范围为0xDC00~0XDFFF。例如0x10437,减去0x10000后的高低位分别为0x1和0x37,分别加上0xD800和0xDC00的结果是0xD801和0xDC37。

        我们最初用的UTF-8是一种可变长度的编码方法。由于UTF-8编码方式只占用了1字节,因此要表达完数量高达0x10FFFF的字符集,它采用了一种前缀编码的方式。这个方法可以用1~4字节表示字符个数为0x10FFFF的Unicode字符集(IOS 10646)。为了尽量节约空间,常用的字符通常用1~2字节就能表达,其他的字符才会用到3~4字节,所以在内存空间可以使用UTF-8,但是计算字符串长度和查找字符串在UTF-8中是一个令人头疼的问题。下标展示了UTF-8对应的范围。

代码范围(16进制) UTF-8(二进制) 备注
000000~00007F共128个字符 0zzzzzzz ASCII字符范围,字节由0开始
000080~0007FFF共1920个字符 110yyyyy  10zzzzzz 第1字节由110开始,接着的字节由10开始

000800~00D7FF 00E000~00FFFF

共61440个字符

1110xxxx  10yyyyyy

10zzzzzz

第1字节由1110开始,接着的字节由10开始

010000~10FFFF

共1048576个字符

11110www  10xxxxxx

10yyyyyy  10zzzzzz

第1字节由11110开始,接着的字节由10开始

使用新字符类型char16_t和char32_t

        对于UTF-8编码方式而言,普通类型似乎是无法满足需求的,毕竟普通类型无法表达边长的内存空间。所以一般情况下我们直接使用基本类型char来进行处理,而C++11之前也没有一个针对UTF-16和UTF-32的字符类型。

        C++11还为3种编码提供了新前缀用于声明3种编码字符和字符串的字面值,它们分别是UTF-8的前缀u8、UTF-16的前缀u、UTF-32的前缀U

/*下面一行代码在C++11标准中编译不过,因为在C++11标准中u8只能作为字符串字面值的前缀,而无法
作为字符的前缀。这个问题直到C++17才得到解决*/
char urf8c = u8'a';    //C++17标准
/*下面这行代码在C++中编译不过,因为存储“好”需要2个字节*/
//char utf8c = u8'好';
char16_t utf16c = u'好';
char32_t utf32c = U'好';
char utf8[] = u8"你好世界";
char16_t utf16[] = u"你好世界";
char32_t utf16[] = U"你好世界";

库对新字符类型的支持

        随着新字符类型加入C++11标准,相应的库函数也加入进来。C11在中增加了4个字符的转换函数,包括:

/*它们的功能分别是多字节字符和UTF-16编码字符互转,以及多字节字符和UTF-32编码字符互转。*/
size_t mbrtoc16();
size_t c16rtomb();
size_t mbrtoc32();
size_t c32rtomb();
/*在C++11中,我们也可以通过包含来使用这四个函数。当然C++11中也添加了C++风格的转发
方法std::wstring_convert以及std::codecvt。使用类模板std::wstring_convert以及std::codecvt
相结合可以对多字节字符串和宽字符串进行转换。需要注意的是它们在C++17中已经不推荐使用了,所以应
该尽量避免使用它们。*/

       除此之外,C++标准库的字符串也加入了对新字符类型的支持,例如:

/*使用using关键字声明类型的别名。类似于typedef关键字,平常在程序时C++更推荐使用using*/
using u16string = basic_string;
using u32string = basic_string;
using wstring = basic_string;

        掌握这3种不同的Unicode字符类型会让我们在使用C++处理字符、字符串以及文本方面更加游刃有余。比如当你在为处理文本文件中UTF-32编码的字符而感到头疼时,采用新标准中char32_t和u32string也许问题就是迎刃而解。

char8_t(C++20引入)

        使用char类型来处理UTF-8字符虽然可行,但是也会带来一些困扰,比如当库函数需要同时处理多种字符时必须采用不同的函数名称以区分普通字符和UTF-8字符。C++20新引入char8_t可以解决以上问题,它可以替代char作为UTF-8的字符类型。char8_t具有和unsigned char相同的符号属性、存储大小、对齐方式以及整数转换等级。引入char8_t类型后,在C++17环境下可编译的UTF-8字符相关的代码会出现问题,例如:

char str[] = u8"text"; //C++17编译成功,C++20编译失败,需要char8_t
char c = u8'c';
/*当然反过来也不行*/
char8_t c8a[] = "text"; //C++20编译失败,需要char
char8_t c8 = 'c';

        另外,为了匹配新的char8_t字符类型,库函数也有相应的增加。例如:

size_t mbrtoc8();
size_t c8rtomb();

using u8string = basic_string;

        最后需要说明的是上面的这些离职只是C++标准库为新字符类型新增代码的冰山一角,标准库代码,包括等等都有对其的支持。

你可能感兴趣的:(C++,C++)