【发布时间】:2011-05-18 11:52:52
【问题描述】:
如果我想在 Windows 上进行以下工作,正确的语言环境是什么以及如何检测它是否实际存在: Does this code work universaly, or is it just my system?
【问题讨论】:
标签: c++ windows unicode utf-8 locale
如果我想在 Windows 上进行以下工作,正确的语言环境是什么以及如何检测它是否实际存在: Does this code work universaly, or is it just my system?
【问题讨论】:
标签: c++ windows unicode utf-8 locale
尽管对命名语言环境没有很好的支持,但 Visual Studio 2010 确实包含 C++11 所需的 UTF-8 转换方面:std::codecvt_utf8 用于 UCS2,std::codecvt_utf8_utf16 用于 UTF-16:
#include <fstream>
#include <iostream>
#include <string>
#include <locale>
#include <codecvt>
void prepare_file()
{
// UTF-8 data
char utf8[] = {'\x7a', // latin small letter 'z' U+007a
'\xe6','\xb0','\xb4', // CJK ideograph "water" U+6c34
'\xf0','\x9d','\x84','\x8b'}; // musical sign segno U+1d10b
std::ofstream fout("text.txt");
fout.write(utf8, sizeof utf8);
}
void test_file_utf16()
{
std::wifstream fin("text.txt");
fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf8_utf16<wchar_t>));
std::cout << "Read from file using UTF-8/UTF-16 codecvt\n";
for(wchar_t c; fin >> c; )
std::cout << std::hex << std::showbase << c << '\n';
}
void test_file_ucs2()
{
std::wifstream fin("text.txt");
fin.imbue(std::locale(fin.getloc(), new std::codecvt_utf8<wchar_t>));
std::cout << "Read from file using UTF-8/UCS2 codecvt\n";
for(wchar_t c; fin >> c; )
std::cout << std::hex << std::showbase << c << '\n';
}
int main()
{
prepare_file();
test_file_utf16();
test_file_ucs2();
}
此输出,在我的 Visual Studio 2010 EE SP1 上
Read from file using UTF-8/UTF-16 codecvt
0x7a
0x6c34
0xd834
0xdd0b
Read from file using UTF-8/UCS2 codecvt
0x7a
0x6c34
0xd10b
Press any key to continue . . .
【讨论】:
【讨论】:
MultiByteToWideChar 不使用当前的 ANSI 代码页。它的第一个参数是要使用的代码页,there UTF-8 (65001) 是允许的。
wchar_t 专门定义为 16 位类型。 C(和 C++)标准要求 wchar_t 能够保存 all 支持的编码中的 any 有效字符。但是没有办法将所有的 Unicode 字符编码为 16 位 - 就是无法做到。因此,Windows C 和 C++ 库不实际上支持任何类型的 Unicode。如果你想在 Windows 上使用 Unicode,你必须跳出 C 和 C++ 库。是的,这很愚蠢,但是您对 Microsoft 有什么期望? :P
wchar_t 和 UTF-16。它们不是同一件事。 UTF-8 和 UTF-16 是编码所有 Unicode 代码点的两种不同方式(其中 far 不仅仅是 65535)。您至少需要 24 位来表示所有 1,000,000 多个 Unicode 代码点。 UTF-16 中的“16”not 表示所有字符都只能使用 16 位表示(例如,某些 Unicode 字符需要 32 位 [两个 16 位 代码单元 ]使用 UTF-16 编码时)。但是 C++ 库需要 wchar_t 才能唯一地表示 每个 支持的字符。
wchar_t 字符串解释为 UTF-16 编码数据,但C 和 C++ 库 不。如果他们这样做了,那么您可以使用 UTF-8 作为 C 和 C++ 库的语言环境。但是,你不能。这就是您的问题的答案;)
在过去,UTF-8(和其他一些代码页)不允许作为系统语言环境,因为
Microsoft 表示,UTF-8 语言环境可能会破坏某些函数,因为它们被编写为假设多字节编码每个字符使用不超过 2 个字节,因此代码页具有更多字节,例如 UTF-8(以及 GB 18030、cp54936 ) 无法设置为语言环境。
https://en.wikipedia.org/wiki/Unicode_in_Microsoft_Windows#UTF-8
不过,微软逐渐引入了UTF-8 locale support,并开始再次推荐 ANSI API (-A),而不是像以前那样的 Unicode (-W) 版本
直到最近,Windows 一直强调“Unicode”
-W变体而不是-AAPI。但是,最近的版本使用 ANSI 代码页和-AAPI 作为向应用程序引入 UTF-8 支持的一种方式。如果为 UTF-8 配置 ANSI 代码页,则-AAPI 以 UTF-8 运行。此模型的优势在于支持使用-AAPI 构建的现有代码,无需任何代码更改。-A vs. -W APIs
首先,他们添加了一个“Beta:使用 Unicode UTF-8 支持全球语言”复选框,因为 Windows 10 Insider build 17035 用于将语言环境代码页设置为 UTF-8
要打开该对话框,请打开开始菜单,输入“区域”并选择区域设置 > 其他日期、时间和区域设置 > 更改日期、时间或数字格式 > 管理
启用后,您可以像往常一样拨打setlocal:
从 Windows 10 build 17134(2018 年 4 月更新)开始,通用 C 运行时支持使用 UTF-8 代码页。这意味着传递给 C 运行时函数的
char字符串将需要 UTF-8 编码的字符串。要启用 UTF-8 模式,请在使用setlocale时使用“UTF-8”作为代码页。例如,setlocale(LC_ALL, ".utf8")将使用当前默认的 Windows ANSI 代码页 (ACP) 作为语言环境,使用 UTF-8 作为代码页。
您也可以在旧的 Windows 版本中使用它
要在 Windows 10 之前的操作系统(例如 Windows 7)上使用此功能,您必须使用 app-local deployment 或使用版本 17134 或更高版本的 Windows SDK 进行静态链接。对于 17134 之前的 Windows 10 操作系统,仅支持静态链接。
在 2019 年后期,他们增加了程序使用 UTF-8 语言环境的功能,甚至无需在上面设置 UTF-8 beta 标志。使用 MSVC 编译时可以使用 /execution-charset:utf-8 或 /utf-8 选项,或者在 appxmanifest 中设置 ActiveCodePage 属性
【讨论】:
/utf-8 选项似乎与复选框无关。它设置了二进制文件的执行和源字符集,但我可能错了。
根据MSDN,它将被命名为“english_us.65001”。但是代码页 65001 在 Windows 上有些不稳定。
【讨论】:
MessageBoxA("Hellö")。但是,它有明确的支持:MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, utf8input.c_str(), ...