乐途乐途
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
主页
  • 计算机基础

    • TCP/IP
    • Linux
    • HTTP
  • 数据库

    • SQL
    • MySQL 5.7
  • 编程语言

    • C
    • C++
    • Java SE
    • Python2
    • Python3
  • 数据格式

    • JSON
    • XML
  • 认证与安全

    • JWT
  • 工具

    • Markdown
  • Git

    • GitFlow
  • Quartz

    • Quartz
  • Java

    • Maven 入门
    • Maven 进阶
    • MyBatis
    • Spring
    • Spring MVC
  • Java

    • Spring Boot
    • Spring Cloud
    • Spring Cloud Alibaba
    • Spring Security
    • Spring AI
    • Spring Batch
    • Kafka
    • Java 设计模式
  • 缓存

    • Redis
  • 搜索引擎

    • Elasticsearch
  • 分布式协调

    • ZooKeeper
联系
阿里云
  • C++ 学习路径
  • 第1章 C++概述与开发环境

    • C++ 语言概述与编译模型
    • 第一个 C++ 程序与规范
    • 开发环境配置
    • 预处理指令详解
  • 第2章 基本语法与类型系统

    • 变量与基本类型
    • 类型转换
    • 枚举类型
    • 引用与指针
    • 数组与 stdarray
    • 字符串与原始字符串字面量
    • const 与 constexpr
    • nullptr 与空指针
    • 类型推导 auto 与 decltype
    • 基于范围的 for 循环
    • 值类别全面解析
    • char16_t 与 char32_t
    • static_assert 编译期断言
  • 第3章 函数与重载

    • 函数声明与定义
    • 函数重载
    • 默认参数与内联函数
    • Lambda 表达式
    • 函数对象与 stdfunction
    • 后置返回类型与 noexcept
  • 第4章 类与对象

    • 类的基本定义
    • 构造函数与析构函数
    • 拷贝控制
    • 移动构造函数与移动赋值
    • 列表初始化与类内初始化器
    • 静态成员与嵌套类
    • 友元
    • =default 与 =delete
  • 第5章 继承与多态

    • 继承基础
    • 虚函数与多态
    • 虚函数表与动态绑定原理
    • 虚析构函数
    • 抽象类与纯虚函数
    • 多重继承与虚继承
    • 继承构造函数
  • 第6章 运算符重载

    • 运算符重载基础
    • 算术与关系运算符重载
    • 赋值与移动运算符重载
    • 特殊运算符重载
  • 第7章 模板与泛型编程

    • 函数模板
    • 类模板
    • 模板特化与偏特化
    • 可变参数模板
    • 别名模板与模板模板参数
    • SFINAE 与类型萃取
    • 依赖名与 typename/template 关键字
  • 第8章 异常处理

    • 异常处理机制
    • noexcept 与异常安全
    • RAII 与异常安全实践
  • 第9章 内存管理与智能指针

    • 动态内存与内存分区
    • RAII 惯用法
    • unique_ptr
    • shared_ptr 与 weak_ptr
    • 内存管理最佳实践
  • 第10章 右值引用与移动语义

    • 右值引用与值类别深度解析
    • std::move 原理与使用
    • 完美转发与 std::forward
    • 移动语义性能对比与最佳实践
  • 第11章 STL容器

    • vector 深度剖析
    • deque 内部机制
    • list 与 forward_list
    • map 与 set 深度解析
    • unordered 容器与哈希原理
    • array 与 tuple
    • 容器适配器
    • 容器选择全景指南
  • 第12章 STL算法与迭代器

    • 迭代器体系全解
    • 非变异算法
    • 变异算法
    • 排序与二分算法
    • Lambda 与算法组合
    • std::random 随机数库
    • 自定义迭代器开发
  • 第13章 IO流与文件

    • 标准 IO 流
    • 格式化输出控制
    • 文件流操作
    • 字符串流
    • std::regex 正则表达式
  • 第14章 并发与多线程

    • thread 基础与线程管理
    • mutex 与 lock_guard
    • unique_lock 与 condition_variable
    • thread_local 线程局部存储
    • atomic 与内存序
    • future 与 async 异步编程
    • std::chrono 时间库
  • 第15章 现代C++新特性

    • 从 C++11 到 C++20 演进路线
    • C++14 关键新特性
    • C++17 关键新特性
    • C++20 核心特性速览
  • 第16章 面试考点与最佳实践

    • C++ 综合最佳实践清单
    • 高频面试题精讲
    • 多线程面试题与实战
    • 内存管理常见陷阱与排查
  • 附录

    • C++ 核心知识点
    • C++ 专业术语

char16_t 与 char32_t

定义与作用

char16_t 和 char32_t 是 C++11 引入的两种新字符类型,分别用于明确表示 UTF-16 编码单元(至少 16 位)和 UTF-32 编码单元(至少 32 位),解决了 wchar_t 在不同平台上宽度不一致的跨平台痛点。

char16_t ch16 = u'飞';         // UTF-16 编码单元
char32_t ch32 = U'翔';         // UTF-32 编码单元
std::u16string s16 = u"飞翔科技";
std::u32string s32 = U"FEIXIANG";
字符类型宽度编码字面量前缀字符串类型
char≥ 8 位实现定义(通常 ASCII/UTF-8)无 / u8(C++17)std::string
char16_t≥ 16 位UTF-16ustd::u16string
char32_t≥ 32 位UTF-32Ustd::u32string
wchar_t实现定义实现定义Lstd::wstring

核心原理

为什么需要 char16_t / char32_t

Unicode 编码单元与码点

类型关系

char16_t 和 char32_t 是独立的基础类型,不是 typedef。这意味着:

  • 它们与 char / wchar_t 不共享重载决议
  • 指针类型不兼容(char16_t* 不能隐式转为 char*)
  • 需要显式转换
// char16_t 和 char32_t 是独立类型
static_assert(!std::is_same<char16_t, unsigned short>::value
              || sizeof(wchar_t) != sizeof(char16_t),
              "char16_t 不是 typedef");

// 指针类型互不兼容
char16_t* p16;
// char* p = p16;  // 编译错误:类型不兼容

完整示例

示例一:多语言用户信息处理

场景说明:黄俪为飞翔科技设计国际化用户界面,需要正确处理中英日韩等多种语言字符。

#include <iostream>
#include <string>
#include <codecvt>
#include <locale>
#include <iomanip>

void showCharInfo(const std::string& label, const char16_t* s16) {
    std::cout << label << ": ";
    while (*s16) {
        std::cout << std::hex << std::setfill('0')
                  << std::setw(4) << static_cast<unsigned>(*s16) << " ";
        ++s16;
    }
    std::cout << std::dec << std::endl;
}

int main() {
    std::cout << "===== 飞翔科技多语言支持 =====" << std::endl;

    // ---- char16_t 与 UTF-16 ----
    char16_t name16[] = u"孔蓝";  // UTF-16 字符串
    std::u16string product16 = u"飞翔智能助手 v2.0";

    std::cout << "\n[char16_t 数据]" << std::endl;
    std::cout << "sizeof(char16_t) = " << sizeof(char16_t) << " 字节" << std::endl;

    showCharInfo("孔蓝 (UTF-16)", name16);

    // ---- char32_t 与 UTF-32 ----
    char32_t name32[] = U"赵鸣";  // UTF-32 字符串
    std::u32string slogan32 = U"愿你朝华相顾,愿你前程似锦。";

    std::cout << "\n[char32_t 数据]" << std::endl;
    std::cout << "sizeof(char32_t) = " << sizeof(char32_t) << " 字节" << std::endl;

    for (const auto& ch : name32) {
        if (ch == 0) break;
        std::cout << "U+" << std::hex << std::setfill('0')
                  << std::setw(8) << static_cast<uint32_t>(ch)
                  << std::dec << " ";
    }
    std::cout << std::endl;

    // ---- wchar_t 对比 ----
    std::cout << "\n[平台对比]" << std::endl;
    std::cout << "sizeof(char)    = " << sizeof(char)    << " 字节" << std::endl;
    std::cout << "sizeof(wchar_t) = " << sizeof(wchar_t) << " 字节"
              << " (实现定义)" << std::endl;
    std::cout << "sizeof(char16_t) = " << sizeof(char16_t) << " 字节"
              << " (始终16位)" << std::endl;
    std::cout << "sizeof(char32_t) = " << sizeof(char32_t) << " 字节"
              << " (始终32位)" << std::endl;

    std::cout << "\n[结论]" << std::endl;
    if (sizeof(wchar_t) == 2) {
        std::cout << "  当前平台 wchar_t 是 16 位 (如 Windows)" << std::endl;
        std::cout << "  wchar_t 宽度 == char16_t 宽度,但类型不同" << std::endl;
    } else {
        std::cout << "  当前平台 wchar_t 是 32 位 (如 Linux/macOS)" << std::endl;
        std::cout << "  wchar_t 宽度 == char32_t 宽度,但类型不同" << std::endl;
    }

    return 0;
}

预期输出(Windows):

===== 飞翔科技多语言支持 =====

[char16_t 数据]
sizeof(char16_t) = 2 字节
孔蓝 (UTF-16): 5b54 84dd

[char32_t 数据]
sizeof(char32_t) = 4 字节
U+00008d75 U+00009e23

[平台对比]
sizeof(char)    = 1 字节
sizeof(wchar_t) = 2 字节 (实现定义)
sizeof(char16_t) = 2 字节 (始终16位)
sizeof(char32_t) = 4 字节 (始终32位)

[结论]
  当前平台 wchar_t 是 16 位 (如 Windows)
  wchar_t 宽度 == char16_t 宽度,但类型不同

逐段分析:

  • char16_t 始终 16 位,char32_t 始终 32 位——无论平台
  • u"..." 创建 UTF-16 字符串字面量,类型为 const char16_t[N]
  • U"..." 创建 UTF-32 字符串字面量,类型为 const char32_t[N]
  • Windows 上 wchar_t 是 16 位(UTF-16),Linux/macOS 上是 32 位(UTF-32)——这就是引入 char16_t / char32_t 的根本原因
  • 即使 wchar_t 和 char16_t 宽度相同,它们仍是不同的独立类型,指针不能隐式互转

示例二:文本编码转换与字符计数

场景说明:李眉需要统计用户反馈中的实际字符数(码点数),区分 UTF-16 编码单元数和 Unicode 码点数。

#include <iostream>
#include <string>
#include <cstdint>
#include <vector>

// 统计 UTF-16 字符串中的 Unicode 码点数
// UTF-16 中,BMP 外字符用代理对表示(2 个 char16_t = 1 个码点)
std::size_t countCodePoints(const std::u16string& s) {
    std::size_t count = 0;
    for (std::size_t i = 0; i < s.size(); ++i) {
        char16_t ch = s[i];
        // 高代理项范围: 0xD800 - 0xDBFF
        // 低代理项范围: 0xDC00 - 0xDFFF
        if (ch >= 0xD800 && ch <= 0xDBFF) {
            // 代理对的高位部分,跳过低位部分
            ++i;  // 跳过下一个 char16_t(低代理项)
        }
        ++count;
    }
    return count;
}

int main() {
    std::cout << "===== 飞翔科技用户反馈分析 =====" << std::endl;

    // 中文(均在 BMP 内)
    std::u16string feedback = u"产品很好用,界面美观。";
    std::cout << "\n[中文反馈]" << std::endl;
    std::cout << "文本: 产品很好用,界面美观。" << std::endl;
    std::cout << "char16_t 单元数: " << feedback.size() << std::endl;
    std::cout << "Unicode 码点数:  " << countCodePoints(feedback) << std::endl;
    std::cout << "(中文在 BMP 内,每个字 = 1 个 char16_t)" << std::endl;

    // 混合字符
    std::u16string mixed = u"飞翔 FEIXIANG 2018";
    std::cout << "\n[混合文本]" << std::endl;
    std::cout << "文本: 飞翔 FEIXIANG 2018" << std::endl;
    std::cout << "char16_t 单元数: " << mixed.size() << std::endl;
    std::cout << "Unicode 码点数:  " << countCodePoints(mixed) << std::endl;

    // 显示字符与编码
    std::cout << "\n[字符编码明细]" << std::endl;
    char16_t special[] = u"飞";
    std::cout << "'飞' 的 UTF-16: U+"
              << std::hex << static_cast<uint16_t>(special[0])
              << std::dec << std::endl;

    // char32_t —— 每个字符恰好一个单元
    std::u32string feedback32 = U"产品很好用,界面美观。";
    std::cout << "\n[使用 char32_t 计数]" << std::endl;
    std::cout << "char32_t 单元数 = Unicode 码点数 = "
              << feedback32.size() << std::endl;
    std::cout << "(char32_t 定长编码,1 单元 == 1 码点)" << std::endl;

    return 0;
}

预期输出:

===== 飞翔科技用户反馈分析 =====

[中文反馈]
文本: 产品很好用,界面美观。
char16_t 单元数: 11
Unicode 码点数:  11
(中文在 BMP 内,每个字 = 1 个 char16_t)

[混合文本]
文本: 飞翔 FEIXIANG 2018
char16_t 单元数: 16
Unicode 码点数:  16

[字符编码明细]
'飞' 的 UTF-16: U+98de

[使用 char32_t 计数]
char32_t 单元数 = Unicode 码点数 = 11
(char32_t 定长编码,1 单元 == 1 码点)

逐段分析:

  • UTF-16 是变长编码:BMP(基本多语言平面)内的字符用 1 个 char16_t,BMP 外的字符用 2 个 char16_t(代理对)
  • 中文常用汉字均位于 BMP 内,每个汉字恰好 1 个 char16_t
  • std::u16string::size() 返回的是 char16_t 单元数量,不是 Unicode 码点数量
  • 代理对检测:高位 0xD800–0xDBFF,低位 0xDC00–0xDFFF
  • char32_t 是定长编码,每个 char32_t 恰好对应一个 Unicode 码点——适合需要码点级操作的场景

易错场景与面试考点

易错场景

场景错误表现正确做法
假设 char16_t 和 wchar_t 兼容指针隐式转换失败两者是独立类型,需显式转换或使用对应 API
用 u16string::size() 当字符数BMP 外字符被计为 2遍历时检测代理对,或用 char32_t
遗漏字面量前缀 u / U编译错误,或类型不匹配char16_t* 必须用 u"...",char32_t* 必须用 U"..."
混用 char 和 char16_t编码不一致导致乱码统一编码策略,在边界处显式转换
codecvt 转换已弃用(C++17)使用了标记为 deprecated 的设施C++17 后考虑第三方库(如 ICU)

常见面试问题

  1. 为什么 C++11 要引入 char16_t 和 char32_t?——wchar_t 在不同平台宽度不同(Windows 16 位、Linux 32 位),导致跨平台行为不一致。char16_t 和 char32_t 提供明确的宽度和编码语义。

  2. char16_t 是 uint16_t 的 typedef 吗?——不是。char16_t 是独立的基础类型,与 uint16_t 不共享重载决议,指针不兼容。

  3. UTF-16 中如何正确处理代理对(surrogate pair)?——检测当前 char16_t 是否在高代理项范围(0xD800–0xDBFF),若是则与下一个 char16_t(低代理项 0xDC00–0xDFFF)组合为一个码点。

  4. u8"..." 字面量是什么?——C++17 引入的 UTF-8 字符串字面量,类型为 const char[N](C++20 前)或 const char8_t[N](C++20 起)。

小结

  • char16_t(UTF-16)和 char32_t(UTF-32)提供跨平台一致的 Unicode 编码单元类型
  • 它们是独立基础类型,不是 typedef,与 wchar_t / char 互不兼容
  • u"..." / U"..." 是配套字面量前缀,分别生成 const char16_t[N] 和 const char32_t[N]
  • char32_t 是定长编码(1 单元 = 1 码点),适合需要精确码点操作的场景
  • char16_t 是变长编码(BMP 外需代理对),适合与 Windows API 等 UTF-16 生态对接
上一页
值类别全面解析
下一页
static_assert 编译期断言