随着C++23开始涉足UTF-8源码字符集,以及Windows开始转向UTF-8。C++总算有解决编码问题的苗头了...
问题,由来已久
我喜欢用这个例子,因为代码中的中文的存在,要想代码通用(跨平台),这几行代码的问题可以列一罗筐:
1 2 3 4 5 |
|
老外明显没有中日韩群众的感同身受,不过Beman Dawes
指出:即使是下面这样简单的代码,C++都无法保证其通用性:
1 |
|
由于个人只关注Windows和Linux两个平台,也只涉及MSVC和GCC两种编译器,也基本上被折腾的想吐:
C++23 与 UTF-8
在C++11引入 u8"...."
字面量,C++20引入 char8_t
之后
C++23 开始:Support for UTF-8 as a portable source file encoding,详见P2295R6
简单地说,从1998年C++标准化,直到二十五年后,才开始解决源码字符集这一基本问题。
MSVC 与 UTF-8
MSVC对UTF-8支持有两个阶段:
MSVC2010(UTF-8基本可用)
- 引入了
#pragma execution_character_set("utf-8")
支持执行字符集 - 支持带BOM的 utf-8 源码字符集
MSVC2015 Update1(UTF-8可用)
- 引入了
/source-charset:utf-8
与/execution-charset:utf-8
- 或者更简单的
/utf-8
选项
但是这也只是解决了窄字符串的执行字符集问题,Windows下API使用UTF-16,而其他平台下使用UTF-8,还是一个大问题
Window API 与 UTF-8
我们知道,Win32 API 通常同时支持 -A
和 -W
两种变体。
-A
变体识别系统上配置的 ANSI 代码页,并支持char*
,而-W
变体则在 UTF-16 编码下工作,支持 WCHAR。
长期以来,Windows 一直强调使用 "Unicode" 的 -W
变体,而不是 -A
API。(这和其他系统下使用窄字符串UTF8不兼容,编写跨平台代码会很头疼)
然而,最近的版本开始使用 ANSI 代码页和 -A
API 来为应用程序引入 UTF-8 支持。如果 ANSI 代码页配置为 UTF-8,那么 -A
API 通常会以 UTF-8 操作。这种模式的好处在于,能够支持使用 -A
API 构建的现有代码,无需进行代码更改。
看起来,Windows以后可能推荐直接使用-A
的API。
注意设置CodePage为 CP_UTF8,对Win32程序来说,注意设置 manifest 文件
1 2 3 4 5 6 7 8 9 |
|
关于UTF-8
UTF-8由肯·汤普森(Ken Thompson)和罗布·派克(Rob Pike)于1992年设计。他们的目标是:
- 兼容性:与ASCII完全兼容(ASCII的字符直接映射为单字节的UTF-8编码)。
- 灵活性:支持所有Unicode字符。
- 效率:对常用字符(如英文字母、数字)使用较少的存储空间。
- 无字节序问题:UTF-8以字节为单位编码,不依赖于字节序(大端或小端)。
字节数 | Unicode 范围 | 二进制格式 |
---|---|---|
1 字节 | U+0000 ~ U+007F | 0xxxxxxx |
2 字节 | U+0080 ~ U+07FF | 110xxxxx 10xxxxxx |
3 字节 | U+0800 ~ U+FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
4 字节 | U+10000 ~ U+10FFFF | 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx |
注意:在UTF-8被首次定义时(RFC 2279),它的设计目标是能够编码到整个31位的空间(即支持码点范围为 U+000000 到 U+7FFFFFFF)。因此,UTF-8最初允许最大6个字节来表示一个字符。
但是 Unicode标准(从版本3.1开始)将码点范围限制在 U+0000 到 U+10FFFF(使用21位空间),这意味着最多需要4个字节就能编码所有Unicode字符。
这个改动与UTF-16的设计限制密切相关(如果哪一天字符不够用了,废掉UTF-16,只保留UTF-32和UTF-8就行了,那时UTF-8可以恢复成6字节)。
参考
- https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2295r6.pdf
- https://learn.microsoft.com/en-us/windows/apps/design/globalizing/use-utf8-code-page
- https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170
- https://en.wikipedia.org/wiki/UTF-8