C++20中如何用char8_t存储表情符号并输出?
一、为什么std::cout输出char32_t会报错?
你遇到的错误是因为std::cout是基于char(对应UTF-8)的输出流,C++标准并没有为它提供直接输出char32_t类型的重载,反而把对应的operator<<标记为删除状态,所以直接写std::cout << c(c是char32_t类型)会触发「使用已删除函数」的编译错误。
解决方法
如果想输出char32_t对应的字符,需要先把UTF-32编码的char32_t转换为UTF-8字符串再输出,比如用C++标准库的字符转换工具:
#include <iostream> #include <string> #include <codecvt> #include <locale> int main() { char32_t c = U'😋'; // 将UTF-32转为UTF-8字符串 std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv; std::string utf8_str = conv.to_bytes(c); std::cout << utf8_str << std::endl; return 0; }
注意:C17中
std::codecvt被标记为弃用,C20已移除。如果用C++20及以上版本,可以手动实现UTF-32到UTF-8的转换,也可以通过输出码点数值来调试:std::cout << static_cast<uint32_t>(c)。
二、为什么表情符号不能存入char8_t或char16_t的字符字面量?
核心原因是表情符号😋的Unicode码点是U+1F60B,属于「补充平面」(码点范围U+10000~U+10FFFF),超出了单个char16_t或char8_t的存储能力:
char16_t的限制:它对应UTF-16编码,单个
char16_t只能存储基本多语言平面(U+0000~U+FFFF)的码点。补充平面的码点需要用两个char16_t组成的代理对表示,所以u'😋'这种单个字符字面量会报错——编译器无法把需要两个单元的编码塞进一个char16_t里。正确的做法是用字符串字面量u"😋",它的类型是const char16_t[],包含完整的代理对。char8_t的限制:它对应UTF-8编码的单个字节。而😋的UTF-8编码是4个字节(
0xF0 0x9F 0x98 0x8B),单个char8_t只能存其中一个字节,无法容纳整个表情符号。u8'😋'这种字符字面量要求是单个UTF-8字节单元,自然会编译失败。正确的写法是用字符串字面量u8"😋",类型是const char8_t[],包含完整的4个字节编码。
正确示例代码
// 正确存储表情符号的方式 const char16_t* c1 = u"😋"; const char8_t* c2 = u8"😋"; auto c3 = u"😋"; // 类型为const char16_t[] auto c4 = u8"😋"; // 类型为const char8_t[]
内容的提问来源于stack exchange,提问作者Sheldon

