C/C++ 中的跨平台 unicode:使用哪种编码?

Posted

技术标签:

【中文标题】C/C++ 中的跨平台 unicode:使用哪种编码?【英文标题】:Cross-platform unicode in C/C++: Which encoding to use? 【发布时间】:2012-06-29 11:49:23 【问题描述】:

我目前正在从事一个爱好项目 (C/C++),它应该可以在 Windows 和 Linux 上运行,并且完全支持 Unicode。可悲的是,Windows 和 Linux 使用不同的编码使我们的生活更加困难。

在我的代码中,我尝试使用尽可能通用的数据,以便 Windows 和 Linux 都可以轻松使用。在 Windows 中,wchar_t 默认编码为 UTF-16,在 Linux 中为 UCS-4(如果我错了,请纠正我)。

我的软件打开(_wfopen、UTF-16、Windows、fopen、UTF-8、Linux)并将数据写入 UTF-8 格式的文件。到目前为止,这一切都是可行的。直到我决定使用 SQLite。

SQLite 的 C/C++ 接口允许一个或两个字节的编码字符串 (click)。 当然这不适用于 Linux 中的 wchar_t,因为 Linux 中的 wchar_t 默认为 4 个字节。因此,sqlite的读写需要在Linux下进行转换。

目前,代码因 Windows/Linux 的异常而杂乱无章。我希望坚持在 wchar_t 中存储数据的标准理念:

Windows 中的 wchar_t:文件路径没有问题,读取/写入 sqlite 没有问题。无论如何,都应该以 UTF-8 将数据写入文件。 Linux 中的 wchar_t:由于 UTF-8 编码、读取/写入到 sqlite (wchar_t) 之前的转换以及将数据写入文件时的 windows 相同,文件路径例外。

在阅读 (here) 之后,我确信我应该在 Windows 中坚持使用 wchar_t。但在完成所有这些工作之后,问题就从移植到 Linux 开始了。

目前我正在考虑重做这一切以坚持使用简单的 char(UTF-8),因为它适用于 Windows 和 Linux,请记住我需要在 Windows 中为每个字符串“WideCharToMultiByte”以实现 UTF -8。使用简单的基于 char* 的字符串将大大减少 Linux/Windows 的异常数量。

您有跨平台使用 unicode 的经验吗?关于简单地将数据存储在 UTF-8 中而不是使用 wchar_t 的想法有什么想法吗?

【问题讨论】:

2byte 字符编码绝对是不是 UTF-16。 UTF-16 是 2 到 4 个字节,而 UTF-8 是 1 - 4 个字节。 Windows wchar_t 不是 UTF-16,它是 UCS2。实际上,您可能不会注意到差异,因为 UCS2 涵盖了 BMP,但如果您的用户决定他们必须在 Ogham 或符文中拥有数据... Windows 使用 UTF-16,并且使用 wchar_t 来保存 UTF-16 数据,并且从 Windows 2000 开始就一直这样做。 关于 wchar_t 的用途和用途:***.com/a/11107667/365496 @RemyLebeau:我认为这取决于上下文。例如,您可以设置一个无效的 Unicode 密码,而控制台函数(例如 WriteConsoleOutputCharacter)似乎只允许在每个控制台坐标处使用一个 16 位字(可能解释为 UCS2)。 utf8everywhere.org 几乎可以在网站的 URL 中回答这个问题 :) 【参考方案1】:

我们的软件也是跨平台的,我们也面临类似的问题。我们决定我们的目标是尽可能减少转化次数。这意味着我们在 Windows 上使用wchar_t,在 Unix/Mac 上使用char

我们通过在 Unix 上支持 _TLPCTSTR 以及类似的功能以及在 std::stringstd::wstring 之间轻松转换的通用函数来做到这一点。我们还有一个在大多数情况下使用的通用std::basic_string<TCHAR> (tstring)。

到目前为止,这工作得很好。基本上大多数函数采用tstringLPCTSTR,而那些不采用的函数将从tstring 转换其参数。这意味着大多数时候我们不会转换字符串并传递大多数参数。

【讨论】:

这也是一个可能的解决方案,但仍然有点 hacky。此外,从我的阅读中我了解到,我应该避免使用 TCHAR,因为它是为了通过切换到 MBCS 而不是 Unicode 标志来支持与旧软件的向后兼容性而引入的。 @Fozi,如何在 Ubuntu Linux 上支持 _T?非常感谢。 @ErikKou,在 Unix 或 Linux 中模拟 Windows 宏 _T 的可能解决方案是什么?谢谢。【参考方案2】:

所有平台上的 UTF-8,在 Windows 上即时转换为 UTF-16 是跨平台 Unicode 的常用策略。

【讨论】:

我会稍微调整一下该声明并说:所有平台上的本机编码,与 UTF-8 之间的即时转换。每当字符串离开应用程序(例如写入文件、通过网络套接字发送数据、将输入传递到库等)时,都需要进行即时转换。当然,这一切都取决于具体的场景。 Unicode,更具体地说是 UTF-8,是人类最优雅、最令人印象深刻的创造和社会制度之一。在 UTF-8 成为标准之后开始开发,我感到非常幸运。

以上是关于C/C++ 中的跨平台 unicode:使用哪种编码?的主要内容,如果未能解决你的问题,请参考以下文章

android ndk 中的 unicode 支持

哪种形式的 unicode 规范化适合文本挖掘?

详谈字符编码[一]字符编码中的坑

CodeBlocks

C/C++ _wcsupr_s 函数 – unicode 字符串小写转大写

C/C++ 中的跨平台通用文本处理