说明:
long long
是一种基本数据类型,它通常是一种至少64位的有符号整数类型。在C++中,long long
类型能够存储的数值范围远远超过int
或long
类型,这使得它非常适合存储非常大的整数。
char16_t
和char32_t
是C++11标准引入的两种新的数据类型,它们用于支持Unicode字符集。
接下来我们看看为什么C++11要引入它们。👇
1 long long 类型
1.1 为什么C++11特性中引入long long类型?
在C++11中,long long类型被引入以提供更大的整数值表示能力,它至少具有64位的存储空间,使得我们能够处理更大的整数值。
这个类型在1995年6月之前就由罗兰·哈丁格(Roland Hartinger)提出申请加入C++标准,但当时的C++标准委员会以C语言中不存在这个基本类型为由,拒绝将这个类型加入C++中。
而就在C++98标准出台的一年后,C99标准就添加了long long这个类型,并且流行的编译器也纷纷支持了该类型。在此之后C++标准委员会才计划将整型long long加入标准中。
1.2 关于long long类型大小定义解读
long long大小及相关类型long、int、short的定义解读为:
sizeof(long long)>=sizeof(long)>=sizeof(int)>=sizeof(short)
所以具体的字节数是根据编译器来确定的。在64位系统中,long类型通常为8字节(64位)。
1.3 long long 类型使用详解
long long 的使用较为简单,直接定义即可。参考代码如下:
long long number = 1000000000000000; // 定义一个 long long 类型的变量
2 char16_t、char32_t类型
2.1 为什么引入char16_t和char32_t这两种类型
C++11引入了char16_t和char32_t两种新的数据类型,主要是为了更好地支持国际化和Unicode字符集。详细解读如下:
- Unicode字符集的需要:Unicode是一个国际标准,用于为世界上大多数的书写系统提供一个唯一的码位。它能够表示超过100,000个字符,包括标点符号、数学符号、技术符号以及表情符号等。
- 现有类型的局限性:在C++11之前,标准库主要使用char类型来表示字符,它通常对应于一个字节(8位)。然而,对于Unicode字符集,一个字节的char无法表示所有的字符,因为许多字符的码位超出了一个字节的范围。
- 固定长度字符类型:char16_t是一个至少占用16位的无符号整数类型,它足以表示Unicode的基本多文种平面(BMP),即码位范围在U+0000到U+FFFF之间的字符。char32_t是一个至少占用32位的无符号整数类型,它足以表示Unicode字符集中的所有字符,包括辅助平面的字符,码位范围在U+0000到U+10FFFF之间。
- 编码和解码的便利:引入char16_t和char32_t允许开发者更方便地对Unicode字符串进行编码和解码,因为可以直接以固定长度的字符类型来处理字符,而不需要手动转换字节序或处理多字节序列。
- 与C++标准库的兼容性:C++标准库中的字符串和字符处理函数,如std::string和std::u16string、std::u32string,使用这些新类型来支持Unicode字符串的存储和操作。
- 国际化的支持:通过引入这些类型,C++11为开发者提供了更好的工具来处理国际化问题,使得程序能够更容易地支持多种语言和文化。
- 与C++11标准相协调:C++11标准在多个方面进行了扩展和改进,包括对多线程、基于范围的for循环、基于自动类型的变量声明等的支持。引入char16_t和char32_t是这一改进过程的一部分,以确保C++能够适应现代软件开发的需求。
- 未来兼容性:随着软件国际化需求的增加,对Unicode的支持变得越来越重要。C++11通过引入这些类型,为未来的Unicode扩展和国际化特性打下了基础。
尽管char16_t和char32_t为处理Unicode提供了基础,但在实际应用中,开发者可能仍然需要依赖第三方库,如ICU(International Components for Unicode),来处理更复杂的国际化问题,包括字符编码转换、格式化、排序和搜索等。
2.2 C++98标准中引入了wchar_t,为什么还要引入char16_t和char32_t?
C++98标准中引入的wchar_t类型是为了支持宽字符,它通常用于表示Unicode字符集中的字符。wchar_t的大小至少是16位,但具体的大小(16位、32位或更大)取决于编译器和平台的实现。wchar_t可以存储一个Unicode的码位,足以覆盖基本多文种平面(BMP),但不足以覆盖整个Unicode字符集。
尽管wchar_t在某些情况下可以用于国际化,但它存在一些局限性,这也是C++11引入char16_t和char32_t的原因:
- 大小不统一:wchar_t的大小在不同的平台上可能不同,这可能导致跨平台的可移植性问题。
- 表示范围有限:wchar_t的大小不足以表示所有的Unicode字符,尤其是辅助平面上的字符(码位在U+10000到U+10FFFF之间)。
- 编码形式不明确:wchar_t并没有明确指出其使用的是哪种Unicode转换形式(如UTF-16或UTF-32)。这可能导致在不同的平台上,相同的wchar_t字符串可能有不同的字节序列。
- 国际化支持不足:随着国际化需求的增加,开发者需要一种更加明确和统一的方式来处理Unicode字符。wchar_t在表示和处理Unicode字符串时存在局限性,特别是在处理辅助平面字符时。
- 编码粒度更细:char16_t和char32_t提供了更细的编码粒度。char16_t对应于UTF-16编码,可以表示BMP中的所有字符。char32_t对应于UTF-32编码,可以表示整个Unicode字符集中的所有字符。
- 更好的编码透明度:C++11标准通过引入char16_t和char32_t,以及相应的字符串类型std::u16string和std::u32string,提供了更明确的编码透明度,使得开发者可以更容易地理解和处理Unicode字符串。
- 与C++11标准其他特性的一致性:C++11引入了许多现代化的特性,如基于范围的for循环、自动类型推断、基于右值引用的移动语义等。引入char16_t和char32_t是为了使标准库在国际化支持方面与其他特性保持一致。
- 更好的工具和库支持:随着Unicode和国际化处理工具的发展,char16_t和char32_t提供了更好的支持,使得开发者可以更容易地使用这些工具和库。
总之,尽管wchar_t在某些情况下可以用于国际化,但它的局限性促使C++11引入了char16_t和char32_t,以提供更好的Unicode支持和国际化能力。这些新类型提供了更明确的大小、编码透明度和表示范围,有助于开发者创建更加国际化和可移植的软件。
2.3 char16_t、char32_t使用详解
char16_t和char32_t在C++11中引入,用以支持Unicode字符集。以下是一些使用这些类型的示例场景和代码案例。
2.3.1 创建和操作std::u16string
参考代码如下:
#include <iostream>
#include <string>
int main() {
// 创建一个std::u16string对象
std::u16string u16str = u"Hello, 世界!";
// 访问字符串中的字符
for (char16_t ch : u16str) {
std::cout << "U+" << std::hex << static_cast<uint_least16_t>(ch) << " ";
}
std::cout << std::endl;
// 修改字符串内容
u16str[6] = u'W'; // 将"世界"的"世"改为大写"W"
// 输出修改后的字符串
std::cout << "Modified UTF-16 String: " << u16str << std::endl;
return 0;
}
解读:在这个Demo中,我们首先创建了一个std::u16string对象u16str,它是一个基于char16_t的字符串,用于存储UTF-16编码的文本。我们遍历字符串中的每个字符,并将每个char16_t字符转换为它的十六进制表示形式,然后输出。
接着,我们修改了字符串中的一个字符,将"世"改为大写"W"。UTF-16编码的字符串允许我们像操作普通字符串一样进行修改。
最后,我们输出了修改后的字符串,以展示结果。
2.3.2 使用char32_t和std::u32string
参考代码如下:
#include <iostream>
#include <string>
int main() {
// 使用char32_t的字符串字面量需要前缀U
char32_t ch = U'🌐'; // Unicode字符,表示地球仪
// 创建std::u32string对象
std::u32string str = U"👋🌐"; // 使用u32string存储UTF-32编码的字符串
// 将单个char32_t字符添加到u32string中
str.push_back(ch);
// 遍历字符串并输出每个字符的代码点
for (char32_t c : str) {
std::cout << "U+" << std::hex << static_cast<unsigned int>(c) << " ";
}
std::cout << std::endl;
return 0;
}
解读:
在这个案例中,我们使用了char32_t来表示单个的UTF-32编码字符。UTF-32是一种固定长度的编码形式,每个Unicode字符都使用一个单独的char32_t值表示。
我们创建了一个std::u32string对象来存储UTF-32编码的字符串。std::u32string是C++11标准库中的另一个类模板实例化,用于处理UTF-32编码的字符串。
在遍历字符串时,我们使用static_cast<unsigned int>来获取char32_t的整数值,然后以十六进制格式输出。
2.3.3 转换为UTF-8并输出
由于C++标准库不支持直接将UTF-16或UTF-32转换为UTF-8,这里展示的是如何使用第三方库ICU或者平台相关的函数来进行转换。以下是使用伪代码表示转换逻辑的示例:
#include <iostream>
#include <string>
// 引入ICU头文件(需要安装ICU库)
#include <unicode/unistr.h>
int main() {
// 创建一个UTF-32字符串
std::u32string u32str = U"👋🌐";
// 使用ICU库将UTF-32转换为UTF-8
icu::UnicodeString unicodeStr = icu::UnicodeString::fromUTF32(u32str.data(), u32str.size());
std::string utf8Str;
unicodeStr.toUTF8String(utf8Str);
// 输出UTF-8编码的字符串
std::cout << "UTF-8 String: " << utf8Str << std::endl;
return 0;
}
解读:在这个Demo中,我们创建了一个std::u32string对象u32str,它包含两个辅助平面的Unicode字符(地球仪和挥手表情)。我们使用ICU库的UnicodeString类来执行从UTF-32到UTF-8的转换。fromUTF32方法接受UTF-32编码的字符数组和长度,创建一个UnicodeString对象。然后,我们使用toUTF8String方法将UnicodeString对象转换为UTF-8编码的std::string。最后,我们输出了转换后的UTF-8字符串。但是注意:
- ICU(International Components for Unicode)是一个提供Unicode支持的成熟库,它包含了许多国际化和Unicode相关的工具和函数。
- C++标准库本身不提供UTF-16、UTF-32到UTF-8的直接转换,因此通常需要依赖第三方库或平台特定的实现。
这些Demo展示了char16_t和char32_t在C++中的常见用法,包括创建和操作基于这些类型的字符串,以及如何将它们转换为UTF-8编码的字符串以便于输出和进一步处理。