Character Literal & String Literal in C++

Ordinary Character Literals and String Literals

Ordinary Character Literals

在我们了解了整数型字面量和浮点型字面量之后,这篇文档我们来学习什么是字符字面量和字符串字面量。首先,我们来看一看最常见的字符字面量和字符串字面量。

std_ascii.png

普通字符字面量就是我们常用 char 类型来表示的标准 ASCII 字符。 char 类型只占 1 个字节,能表示的数值在 0 - 255 这 256 个数字,而用来表示标准的 ASCII 绰绰有余(不包含 EASCII )。普通字符字面量在 C++ 中有这几种表示形式:

char a1 = 'a';      // basic character, ASCII value of 'a' is 97
char a2 = '\x61';   // using escape sequence, equals to '\141' as in octal
char a3 = 0x61;     // direct hexadecimal value, equals to a3 = 97;

第一种形式适合用于表示那些在 ASCII 中可显示的字符,上图从 0x21(32) 到 0x7E(126) 都是可显示字符。而那些不可显示的字符我们通常用转义字符来表示,比如换行符 \n 和水平制表符 \t,你也可以用转移字符表示可显示的字符。因为每个 ASCII 字符在表中都有一个数字与之对应,你也可以直接使用这些数值来对 char 类型变量赋值。

Ordinary String Literals

"String is an array of characters",不难理解,普通字符串字面量就是由普通字符字面量构成的字符序列。这些字符序列要在双引号 " " 中进行表示。里面的字符可以是标准 ASCII 字符和转义字符。普通字符串字面量的类型是 const char[N]const char*。为了知道结尾的位置,编译器会在字符串末尾添加一个空字符 \0

const char* str1 = "Hello, world"; // Same as const char[] str1 = "Hello, World!";
const char* str2 = "Line1\nLine2";
const char* str3 = "Hello,\0world"; // only prints "Hello,"

在这个例子中的三个普通字符串字面量在内存中如下图所示:
string_literal.png
C++11 引入了原始字符串字面量,这也是一种普通字符串字面量。和上面的用双引号表示方法不同的是,原始字符串字面量以 R"()" 的形式表示。允许字符串中包含反斜杠和引号而不用转义。我们接着用上面的例子举例:

const char* str1 = R"(Hello, world)";
const char* str2 = R"(Line1
Line2)";
const char* str3 = R"(Hello,\0world)"; // prints Hello,\0world

UFT-8 Character Literals and String Literals

Unicode 是一个字符集,旨在包含全世界上所有的字符和符号,它兼容 ASCII 。UFT(Unicode Transformation Format) 是一系列用于编码 Unicode 字符的标准。

UFT-8 Character Literals (C++17)

UFT-8 字符字面量能够表示的字符和普通字符字面量能表示的字符是相同的(0x00 - 0x7F),都只能表示标准 ASCII 字符。所以UFT-8 字符字面量的一个字符只占用 1 字节。

UFT-8 表示字面量格式如下:

char a = u8'a'; // until C++20
char8_t a = u8'a'; // since C++20

在 C++20 之前,我们用 char 类型来表示 UFT-8 字符字面量,因为 Unicode 兼容 ASCII 嘛。但是在 C++20 之后,我们用 char8_t 类型来表示 UFT-8 的字符字面量。为了保持统一。

UFT-8 String Literals (C++11)

// Until C++20
const char[] c = u8"Hello, world!";
const char[] c2 = u8R"(Hello, world!)";

// Since C++20
const char8_t[] c = u8"Hello, world!";
const char8_t[] c2 = u8R"(Hello, world!)";

普通和 UFT-8 d 字符串字面量统称为narrow string literals.

Wide Character Literals and String Literals

Wide Character Literals (AKA Long Character Literals)

虽然 char 类型表示的字符还能扩容到 256 个。但是对于世界上这么多字符符号,256 个完全是不够用的。为了表示比普通字符集更大的字符集,在 C++ 中,我们有宽字符或者叫长字符字面量。在不同的平台,宽字符大小的实现可能有所不同,通常是 2 字节(UFT-16)或是 4 字节(UFT-32)。字节数多了,能够表示的字符数量也就指数级别的增多。2 字节宽字符可以表示 65536 个字符,4 字节宽字符可以表示超过 400 万个字符。

宽字符用 wchar_t 类型来表示,我们有下面的例子:

wchar_t a = L'哈'; // Allocate 2/4 bytes of memory depending on the system
std::wcout << a << std::endl;
std::wcout << L'β' << std::endl;

奇怪的是宽字符的前缀不为 W 而是 L,令人百思不得其解。

Wide String Literals

一切尽在不言中。

const wchar_t* c = L"Hello, world!";
const wchar_t* c2 = LR"(Hello, world!)";

UFT-16 and UFT-32 Character Literals (C++11)

你现在知道了字符字面量和字符串字面量表示上的联系,我们最后再来看看 C++ 中的最后两种字符字面量:UFT-16 字符字面量和 UFT-32 字符字面量。

Character Literals

UFT-16 字符用 char16_t 类型表示,单个 char16_t 字符占用 2 字节内存,可以表示 65536 个不同的字符。UFT-32 字符用 char32_t 类型表示,单个 char32_t 字符占用 4 字节内存,可以表示 4,294,967,296 个不同的字符。

UFT-16 和 UFT-32 表示字面量的格式如下:

char16_t a = u'a';
char32_t a = U'a';

String Literals

// UFT-16 string literals
const char16_t* c = u"Hello, world!";
const char16_t* c2 = uR"(Hello, world!)";
// UFT-32 string literals
const char32_t* c = U"Hello, world!";
const char32_t* c2 = UR"(Hello, world!)";