C++20形式的utf-8字符串转宽字符串,不依赖编译器编码形式

默认的char[]编码都是要看编译器编译选项的,你选了ANSI那它就是ANSI,你选了UTF8那它就是UTF8.
compiler-encoding-option
【注意:经典DevC++只支持ANSI编码(痛苦);上图是小熊猫DevC++,则有这个选项】

这一点对我的代码造成了麻烦。我就是要用utf8字符串,无视编译器编码选项,并输出,怎么搞?

先看什么是麻烦的代码:

#include <windows.h>
#include <stdio.h>// 将UTF-8字符串转换为宽字符串(不一定是UTF-16)
wchar_t* utf8_to_wstr(const char* utf8_string) 
{// 获取UTF-8字符串的长度int len = strlen(utf8_string);// 计算所需缓冲区大小int w_size = MultiByteToWideChar(CP_UTF8, 0, utf8_string, len, NULL, 0);// 分配宽字符串缓冲区wchar_t* w_string = (wchar_t*)malloc((w_size + 1) * sizeof(wchar_t));// 将UTF-8多字节转换为宽字符串MultiByteToWideChar(CP_UTF8, 0, utf8_string, len, w_string, w_size);w_string[w_size] = L'\0';  // 添加NULL终止字符return w_string;
}int main() {const char* utf8_string = "Wormwaker创作";// 转换为wchar_t*wchar_t* w_string = utf8_to_wstr(utf8_string);// 使用MessageBoxW显示UTF-16字符串MessageBoxW(NULL, w_string, L"MessageBoxW", MB_OK);// 释放内存free(w_string);return 0;
}

上述代码字符以char类型存储,编码依赖编译器选项。如果为ANSI,则结果为:
failure
如果为UTF-8,才是正确的结果:
success
· 试想,把含类似于这样一段代码的项目(例如一个软件或是一个游戏)代码发给你一个朋友,他一看运行出来是乱码,他第一反应就是你写的有问题,是你的问题。他基本不会考虑自己的编码选项有问题。你可能还要教他怎么调,这将消耗你宝贵的时间。于是,这段代码可能需要变得兼容一点。


随着时代的进步,C++针对utf编码的字符出现了更新:

C++11

1.添加新字符类型 char16_tchar32_t,分别对应utf-16和utf-32编码。同时也添加了相应的std::basic_string,也就是 std::u16stringstd::u32string.
2.添加三种字符串字面量前缀:u, U, 以及 u8,分别对应utf-16, utf-32, utf-8编码。

注意:此时还没有 char8_t !

这时候就可以写这样的代码了:

char16_t utf16c = u'好';
char32_t utf32c = U'好';
char utf8[] = u8"你好世界";
char16_t utf16[] = u"你好世界";
char32_t utf32[] = U"你好世界";

注意!因为没有 char8_t[],所以u8字符串被存在了char[]里。
而且:

C++ 17

到了C++17才添加了对u8前缀的utf-8字符的支持!也就是说,下面这么写必须 是C++17标准:

char utf8c = u8'a'; // C++17标准
//char utf8c = u8'好';

到这里已经可以实现我们想要的兼容性了,不过到最后再一起说

C++ 20

C++20终于把 char8_t 加入到了基本类型中。现如今所有u8的字符和字符串都必须用char8_t系列存储了,不允许使用char了。 也就是说,应该改成这样:

char8_t uft8c = u8'a';  //C++20
const char8_t* pstrUtf8 = u8"Hello World";
std::u8string sutf8 {u8"Hello Universe"};

当然有char8_t那就肯定也一起出了std::u8string.
basic_string

std::basic_string变化详情 - 跳转链接→


最后就是兼容可靠的代码的书写了:
针对C++17标准:

#include <windows.h>
#include <stdio.h>// 将UTF-8字符串转换为宽字符串(不一定是UTF-16)
wchar_t* utf8_to_wstr(const char* utf8_string) 
{// 获取UTF-8字符串的长度int len = strlen(utf8_string);// 计算所需缓冲区大小int w_size = MultiByteToWideChar(CP_UTF8, 0, utf8_string, len, NULL, 0);// 分配宽字符串缓冲区wchar_t* w_string = (wchar_t*)malloc((w_size + 1) * sizeof(wchar_t));// 将UTF-8多字节转换为宽字符串MultiByteToWideChar(CP_UTF8, 0, utf8_string, len, w_string, w_size);w_string[w_size] = L'\0';  // 添加NULL终止字符return w_string;
}int main() {const char* utf8_string = u8"Wormwaker创作";// 转换为wchar_t*wchar_t* w_string = utf8_to_wstr(utf8_string);// 使用MessageBoxW显示UTF-16字符串MessageBoxW(NULL, w_string, L"MessageBoxW", MB_OK);// 释放内存free(w_string);return 0;
}

就看这么一句就行了:

const char* utf8_string = u8"Wormwaker创作";

这样即使编译器默认以ANSI编码EXE,也会单独把这个字符串以UTF-8编码的,达到了想要的效果。

针对≥C++20标准:

#include <windows.h>
#include <stdio.h>// 将UTF-8字符串转换为宽字符串(不一定是UTF-16)
wchar_t* utf8_to_wstr(const char8_t* utf8_string) 
{// 获取UTF-8字符串的长度int len = strlen((const char*)utf8_string);// 计算所需缓冲区大小int w_size = MultiByteToWideChar(CP_UTF8, 0, (const char*)utf8_string, len, NULL, 0);// 分配宽字符串缓冲区wchar_t* w_string = (wchar_t*)malloc((w_size + 1) * sizeof(wchar_t));// 将UTF-8多字节转换为宽字符串MultiByteToWideChar(CP_UTF8, 0, (const char*)utf8_string, len, w_string, w_size);w_string[w_size] = L'\0';  // 添加NULL终止字符return w_string;
}int main() {const char8_t* utf8_string = u8"Wormwaker创作";// 转换为wchar_t*wchar_t* w_string = utf8_to_wstr(utf8_string);// 使用MessageBoxW显示UTF-16字符串MessageBoxW(NULL, w_string, L"MessageBoxW", MB_OK);// 释放内存free(w_string);return 0;
}

要注意的是
1.

const char8_t* utf8_string = u8"Wormwaker创作";

2.在所有const char* (或LPCSTR)的参数处都要把const char8_t* 强转成const char*.

如果你的编译器支持C++20标准,建议就用这第二种。毕竟在未来的标准下都得这么写。

完美解决!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/237297.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

DevOps系列文章 : 使用dpkg命令打deb包

创建一个打包的目录&#xff0c;类似rpmbuild&#xff0c;这里创建了目录deb_build mkdir deb_build目标 我有一个hello的二进制文件hello和源码hello.c, 准备安装到/opt/helloworld目录中 步骤 在deb_build目录创建一个文件夹用于存放我的安装文件 mkdir helloworld在he…

ADS学习笔记(二)——更新中

八、中途容性负载的时延累加 1.原理简述 中途容性负载产生的第一位影响就是下冲噪声&#xff0c;第二位影响是远端信号的接收时间被延迟。电容器与传输线的组合就像一个RC滤波器&#xff0c;所以传输信号10&#xff05;&#xff5e;90&#xff05;上升边将增加&#xff0c;信…

Java-Secruity-2

可以先看这篇文章 Secruity-1&#x1f448; 1、授权 1.1 权限管理 在日常使用的系统中都会涉及到权限相关的操作&#xff0c;管理员有管理员的操作&#xff0c;用户有用户的操作&#xff0c;不同的用户可以使用不同的功能&#xff0c;这需要使用到权限管理。 所以在写接口…

μC/OS-III 里面的环形表

文章目录 1、时钟节拍任务2、定时器列表 μC/OS-III 里面两个地方用到了环形表&#xff0c;时钟节拍任务&#xff0c;定时器列表&#xff0c;通过排序后&#xff0c;效率是非常高的。 以下内容整理自 嵌入式实时操作系统uC/OS-Ⅲ 1、时钟节拍任务 2023/12/21 18:04:16 (1) 该…

【数论】约数

试除法求约数 时间复杂度 O(sqrt(n))。 核心思路是求到较小的约数时&#xff0c;将其对应的较大约数也可以直接求出来&#xff0c; 例如&#xff1a;a/bc&#xff0c;b是a的余数&#xff0c;c也是a的余数 ps&#xff1a;注意bc的情况&#xff0c;要注意去重 void solve() …

JavaGUI(但期末速成版)之事件监听和处理

点击返回标题->JavaGUI期末速成版-CSDN博客 前言 依旧先声明&#xff0c;本篇记录的JavaGUI编程都是十分精简的&#xff0c;内容只取常用的、套路的、应付期末考试的。 我先放两张ppt的原内容。。。 看完&#xff08;我觉得你可能都没看完&#xff09;&#xff0c;摊牌了&a…

赴日IT培训课程 程序员新思路!

先说好&#xff0c;跟国内相比&#xff0c;日本IT并不发达。日本IT是依托着日本传统强势的制造业和政府机关发展的&#xff0c;所以开发的大多数软件也是面向这些的&#xff0c;由于日本人的严谨态度&#xff0c;各种文档的编写层出不穷&#xff0c;不像国内程序员每天没日没夜…

android 新版studio gradle 里面没有offline 勾选项

studio 右边 gradle 上面有个图标可以点击切换

【深度学习】注意力机制(七)Agent Attention

本文介绍Agent Attention注意力机制&#xff0c;Transformer中的Attention模块可以提取全局语义信息&#xff0c;但是计算量太大&#xff0c;Agent Attention是一种计算非常有效的Attention模块。 论文&#xff1a;Agent Attention: On the Integration of Softmax and Linear…

前端手动部署与自动化部署

连接服务器 先购买服务器 安装vscode插件 连接服务器 连接成功 手动部署 安装nginx 启动nginx systemctl start nginx systemctl status nginx systemctl enable nginx启动 检查状态 开机就启动nginx 开始手动部署 配置nginx 成功

走过的2023:在挑战中领悟,在仿徨中成长

转眼间就到了2023年的最后一个月&#xff0c;回顾这短暂而又有意义的一年&#xff0c;可以用12个字总结&#xff1a;在挑战中领悟&#xff0c;在仿徨中成长。这篇文章我会从技术成长、职场生活、读书感悟和个人生活等几个方面&#xff0c;总结一下过去的这一年&#xff0c;梳理…

【玩转TableAgent数据智能分析】——个人体验分享

文章目录 前言上手体验优势不足 再次体验第三次体验第四次体验1、找到高价房源和低价房源的特点&#xff0c;看清民宿行业的整体布局2、了解各个地域的整体价格&#xff0c;优选潜力城市3、对比各个城市的评分&#xff0c;深入了解不同城市的民宿市场特点4、对比不同床型价格&a…

Java AQS 阻塞式锁和相关同步器工具的框架

8 J.U.C Java 并发工具包 AQS 原理 AQS&#xff1a;AbstractQueuedSynchronizer&#xff08;抽象队列同步器&#xff09;&#xff0c;阻塞式锁和相关同步器工具的框架 特点&#xff1a; 用 state 属性来表示资源的状态&#xff08;分独占模式和共享模式&#xff09;&#…

TCP/IP 传输层协议

传输层定义了主机应用程序之间端到端的连通性。传输层中最为常见的两个协议分别是传输控制协议TCP&#xff08;Transmission Control Protocol&#xff09;和用户数据包协议UDP&#xff08;User Datagram Protocol&#xff09;。 TCP协议 TCP是一种面向连接的传输层协议&#…

esp32-s3解决使用蓝牙ble一键配网时,蓝牙ble内存使用的内部空间,空间不足时可采用外部PSRAM

idf.py menuconfig进入到esp32配置界面&#xff0c;配置NimBLE使用外部PSRAM内存即可

pip 离线安装:利用pypi网站进行模块 库的离线安装

离线安装是一种很好的方法&#xff0c;在网络不佳、库版本不明确、复杂库本地编译安装报错时&#xff0c;通过whl文件的下载安装&#xff0c;可以很高效的解决问题。 pypi的网站&#xff1a;https://pypi.org/ 这个网站包含各种你 pip install xxx 的库&#xff0c;离线安装可…

我做了一个在手机灵动岛锁屏看实时网速/步数/下班倒计时/跑步距离/照片/待办/倒计时/手机使用次数/帧率...的软件

我做了一个在手机灵动岛&锁屏看实时网速/步数/下班倒计时/跑步距离/照片/待办/倒计时/手机使用次数/帧率…的软件 Island Widgets 的作用&#xff1a; 提醒您 &#xff1a; 准时下班每天运动陪伴家人保持体重放下手机每日待办当前网速手机使用强度实时热搜现在天气… 初…

Python库学习(十三):爬虫框架Scrapy

微信搜索【猿码记】查看更多文章... 1.介绍 Scrapy是一个用于爬取网站数据的Python框架。它提供了一套强大而灵活的工具&#xff0c;使开发者能够轻松地创建和管理爬虫&#xff0c;从而从网站中提取所需的信息。框架要求Python的版本 3.8 Github Star:49.6k: https://github.c…

【Linux】Linux线程概念和线程控制

文章目录 一、Linux线程概念1.什么是线程2.线程的优缺点3.线程异常4.线程用途5.Linux进程VS线程 二、线程控制1.线程创建2.线程终止3.线程等待4.线程分离 一、Linux线程概念 1.什么是线程 线程是进程内的一个执行流。 我们知道&#xff0c;一个进程会有对应的PCB&#xff0c;…

GEE-Sentinel-2月度时间序列数据合成并导出

系列文章目录 第一章&#xff1a;时间序列数据合成 文章目录 系列文章目录前言时间序列数据合成总结 前言 利用每个月可获取植被指数数据取均值&#xff0c;合成月度平均植被指数&#xff0c;然后将12个月中的数据合成一个12波段的时间数据合成数据。 时间序列数据合成 代码…