在 C++ 中创建同时支持 Unicode 和 ASCII 的库的最佳实践是啥?

Posted

技术标签:

【中文标题】在 C++ 中创建同时支持 Unicode 和 ASCII 的库的最佳实践是啥?【英文标题】:What is the best practice for creating libraries that support both Unicode and ASCII in C++?在 C++ 中创建同时支持 Unicode 和 ASCII 的库的最佳实践是什么? 【发布时间】:2009-09-30 17:59:13 【问题描述】:

我正在编写一些可供内部和客户使用的库,我想知道同时支持 Unicode 和 ASCII 的最佳方法是什么。看起来微软(在 MFC 库中)同时编写了 Unicode 和 ASCII 类,并使用宏在头文件中执行了类似的操作:

#ifdef _UNICODE
#define CString CStringW
#else
#define CString CStringA
#endif

虽然我不是宏的忠实粉丝,但它确实可以胜任。如果我正在使用 STL 编写库,那么编写包含以下内容的标头是否有意义:

#ifdef _UNICODE
#define GetLastErrorString GetLastErrorStringW
#else
#define GetLastErrorString GetLastErrorStringA
#endif

std::string GetLastErrorStringA();
std::wstring GetLastErrorStringW();

或者我应该只发布单独的库,一个用于 ASCII,一个用于 Unicode?

只是想知道在这种情况下人们认为最好的做法是什么。

更新:解决一些 cmets 和问题:

这些将是 C++ 类库。 我认为我需要使用 UTF-16 编码,因为我想支持亚洲字符集。 我实现 Unicode 的原因有两个:1) 所有新的 SDK 都支持 Unicode,我不相信未来的 SDK 或第三方库将来会支持单独的 ASCII 版本。 2) 虽然我们不会完全国际化我们的应用程序,但如果我们能够处理用户输入(如名称)和从包含亚洲字符的路径加载的文件,那就太好了。

【问题讨论】:

您是在开发平面 C 风格的 API 还是一组 C++ 类? 您的示例存在问题:如果您希望有机会编译而不是方法本身(尽管您可能必须使用 #在方法的实现中定义)。 根据我的经验,您不需要将 UTF-16 用于亚洲 (CJK) 字符。我的程序使用多字节 UTF-8 处理它们,没有任何魔法。 【参考方案1】:

我会在内部使库完全使用 Unicode。然后,将存在一组用于 ASCII 的 C++ 适配器类,它们可以转换为 Unicode 实现。

【讨论】:

问题是:这是否需要在内部使用“Unicode”,因为根据编码,普通的 std::string 可能会起作用。【参考方案2】:

如果先将 unicode 字符串转换为 UTF-8,则可以将它们存储在 std::string 中。

只有在与 UTF-16 调用(如 Windows API)交互时才需要 wstring。如果是这种情况,您可以在需要时在本地将字符串转换为 wstrings。这可能有点繁重,但还不错。

【讨论】:

【参考方案3】:

这个问题有点不准确,但是......

首先您必须精确编码。 Unicode 只是字符的表示(每个都关联一个代码点),在应用程序中处理 Unicode 时,您必须选择代码点的表示方式。如果您可以使用 Utf-8,则不必担心宽字符,您可以将数据存储在普通的 std::string 中:)

那么你必须明确你的问题:

您希望支持 Unicode 和 Ascii 条目吗? 或者你在谈论输出? 您是否可以使用 std::locale 来了解您应该以哪种编码输出?

我正在开发一个国际化应用程序(一个网站,带有 c++ 后端...),我们只是在内部使用 std::string。 Ascii 或 Utf-8 的输出取决于翻译文件,但数据表示不会因 iota 而异(计数字符除外,请参阅此主题的 my post)。

真的,我绝对不是宏的粉丝,因为 utf-8 是为了兼容 Ascii,如果你可以选择自己的编码,你就得救了!

【讨论】:

【参考方案4】:

你问的是代码“可理解性”而不是使用 ASCII、UTF-8、16 或 32 位字符。

如果是这样,我更喜欢使代码块尽可能大:这会让人使用“门”(_UNICODE 符号常量)来选择单独的文件,或者至少选择大块代码。在语句中每隔一行左右改变它的位置的代码,或者,天堂禁止,很难理解。

我建议不要使用门来选择包含单独文件的内容

#ifdef _UNICODE
#include "myUniLib.h"
#else
#include "myASCIILib.h"
#endif

因此需要两个甚至三个文件(Unicode 文件、646US (ASCII) 文件,也许还有您的带有上述代码的 nexus 文件)。这是丢失某些东西并导致构建失败的可能性的三倍。

相反,使用文件中的门来选择大块代码:

#ifdef _UNICODE
   ...lotsa code...
#else
   ...lotsa code...
#endif

好的,假设您正在做相反的事情:想知道 char 与 char (UTF-8) 与 W 与 A。您希望有多通用?您提到的 CStrings 仅适用于 Windows 世界。如果您想与 Mac 和 UNIX(OK,Linux)兼容,那么您将遇到困难。

顺便说一句,ASCII ……不再……不是公认的标准。有 ASCII,然后有...... ASCII。如果您指的是过去 UNIX 的 7 位“标准”,那么我发现的最接近的是 ISO-646US。 Unicode 等价物是 ISO-10646。

有些人幸运地将字符编码为 URL:只有 ASCII 字母和数字以及百分号。虽然您必须一直编码和解码,但存储确实是可预测的。有点奇怪,是的,但绝对是创新的。

存在一些语言缺陷。例如,不要依赖大小写是双向的(我不知道正确的词,在这里)。在 Deutsch 中,小写 ß 转换为大写时变为 SS。但是,SS 在小写时会变形为 ss,而不是 ß。土耳其语也有类似的东西。在设计您的应用程序时,不要假设案例翻译可以帮助您。

另外,请记住,语法顺序因语言而异。一句“你好,吉姆!你星期一过得怎么样?”最终可以是“你好!你的,星期一,一切顺利吗,吉姆?”

最后,警告:避免流 IO(std::cin >)。它使您陷入嵌入消息生成器的陷阱,导致本地化变得非常困难。

您提出了正确的问题。你有一个冒险在你面前!最好的!

【讨论】:

以上是关于在 C++ 中创建同时支持 Unicode 和 ASCII 的库的最佳实践是啥?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Perl 在 Windows 中创建 unicode 文件名

Impala 不支持 Unicode 字符

同时在Kubernetes中创建多个持久卷?

Word处理控件Aspose.Words功能演示:使用 Aspose.Words for C++ 在 Qt 应用程序中创建 Word 文档

在 C++ 中的类中创建类对象的动态数组

在递归函数 C++ 中创建向量