在UTF-8内部工作,然后仅在Windows需要时转换为UTF-16有危险吗?

时间:2012-03-08 19:50:58

标签: c++ windows utf-8 cross-platform utf-16

Visual Studio试图坚持使用tchars,当使用UNICODE选项进行编译时,基本上最终会使用Windows和其他API的宽版本。

在应用程序内部使用UTF-8是否存在任何危险(这样可以更轻松地使用C ++ STL,并且还可以实现更易读的跨平台代码),然后只需要使用任何一个时转换为UTF-16 OS API?

我特别询问开发多个操作系统 - 不使用UTF-8的Windows和其他类似Mac的操作系统。

7 个答案:

答案 0 :(得分:2)

正如其他人所说,在内部使用UTF-8,然后在需要调用Windows函数时进行转换没有危险。

但是,请注意,如果您要显示大量文本,那么每次转换的成本可能会变得非常昂贵。 (请记住,您不仅要进行转换,而且还可能需要分配和释放缓冲区来保存临时转换后的字符串。)

我还应该指出STL内置了广泛的字符支持,所以没有理由这样做。 (std :: wstring,et al。)

此外,专门使用UTF-8对英语很好,但如果您计划支持东欧,阿拉伯或亚洲字符集,则您对文本的存储要求可能会比UTF-16更高(到期)更多需要存储三个或四个代码点的字符)。如果您正在处理大量文本,这可能只是一个问题,但需要考虑的事情 - 如果您打算在任何时候通过网络连接传输此文本,那么这一点也是如此。

答案 1 :(得分:1)

由于UTF-8和UTF-16只是编码数字的两种方式(然后被解释为所谓的代码点或字形),来回转换没有任何问题:没有信息丢失。所以不,转换没有危险(当然,只要转换是正确的)。

答案 2 :(得分:1)

我假设您的项目不是文本处理,操作或转换:对于文本处理,选择一个且仅一个编码,在所有平台上都相同,然后在使用时根据需要进行转换要容易得多原生API。

但是如果您的项目不是围绕文本处理/操作/转换,那么在所有平台上对UTF-8的限制并不是最简单的解决方案。

避免在Windows上使用char

如果您在Windows开发中使用char类型,那么所有WinAPI都将使用char

问题是Windows上的char类型用于“历史”应用程序,这意味着预unicode应用程序。

每个char文本都被解释为非Unicode文本,其编码/字符集由Windows用户选择,而不是您的开发者

含义:如果您认为自己正在使用UTF-8,请将该UTF-8 char文本发送到WinAPI以在GUI(和TextBox等)上输出,然后在Windows设置为阿拉伯语(例如),然后您将看到WinAPI无法正确处理您漂亮的UTF-8字符文本,因为该Windows上的WinAPI认为所有char都被解释为Windows-1256编码。

如果您在Windows上使用char,那么您将放弃Unicode ,除非每次调用WinAPI都要通过翻译(通常是通过像GTK +,QT等框架,但它可能是你自己的包装函数。)

优化是所有邪恶的根源,但是,每次与Windows讨论时,将所有UTF-8文本从UTF-16转换为UTF-16在我看来确实是一种无用的悲观化。

替代方案:为什么不在所有平台上使用TCHAR?

您应该做的是使用TCHAR,为Linux / MacOS / Whatever提供类似于tchar.h的标题(在原始tchar.h标题中重新声明宏等等),使用tchar.h标题扩展它,以便您使用标准库对象。例如,我自己的tstring.hpp就像:

// tstring.hpp
#include <string>
#include <sstream>
#include <fstream>
#include <iostream>

#ifdef _MSC_VER
#include <tchar.h>
#include <windows.h>
#else
#ifdef __GNUC__
#include <MyProject/tchar_linux.h>
#endif // __GNUC__
#endif


namespace std
{

#ifdef _MSC_VER

   // On Windows, the exact type of TCHAR depends on the UNICODE and
   // _UNICODE macros. So the following is useful to complete the
   // tchar.h headers with the C++ Standard Library's symbols.

   #ifdef UNICODE

      typedef              wstring        tstring ;
      // etc.
      static wostream &    tcout          = wcout ;

   #else // #ifdef UNICODE

      typedef              string         tstring ;
      // etc.
      static ostream &     tcout          = cout ;

   #endif // #ifdef UNICODE

#else // #ifdef _MSC_VER

    #ifdef __GNUC__

    // On Linux, char is expected to be UTF-8 encoded, so the
    // following simply maps the txxxxx type into the xxxxx
    // type, forwaking the wxxxxx altogether.
    // Of course, your mileage will vary, but the basic idea is
    // there.

    typedef                string         tstring ;
    // etc.
    static ostream &       tcout          = cout ;

    #endif // __GNUC__

#endif // #ifdef _MSC_VER

} // namespace std

Discplaimer:我知道,在std中声明事情是邪恶的,但我还有其他事情要做,而不是在这个特定的主题上迂腐。

使用这些标题,您可以使用C ++标准库与TCHAR工具结合使用,即使用std::tstring,它将在Windows上编译为std::wstring(前提是您已编译)在您希望支持的其他基于UNICODE的操作系统上定义_UNICODEstd::string定义)和char

因此,您可以免费使用平台的原生字符类型。

只要您与TCHAR字符类型无关,就不会有任何问题。

对于你真正想要处理UTF-8与UTF-16的脏点的情况,那么你需要提供转换代码(如果需要)等等。

这通常通过为不同类型和每个OS提供相同功能的重载来完成。这样,在编译时选择了正确的函数。

答案 3 :(得分:1)

如果你的操作系统在其API中带有wid(er)字符,并且你正在编写一个需要国际化支持的应用程序,那么在程序中使用char和UTF-8作为内部表示是完全愚蠢的。你向后使用UTF-8。 UTF-8用于通过操作系统接口以及无法直接处理宽字符的存储和数据交换格式走私Unicode。

答案 4 :(得分:0)

“危险”是UTF-8字符数与ASCII字符数不同。例如,U + 24B62是单个Unicode字符,但扩展为4个UTF-8字节。 (有关其他示例,请参阅here。)

如果你不互换地使用这两者,你会没事的。

答案 5 :(得分:0)

UTF-8是一种表达字符的狂野而古怪的方式。你应该尽可能避免使用它。 Windows API避免使用UTF-8。 (如果你坚持使用'多字节'构建,而不是'unicode'构建,它将为你完成所有转换,因为它可以继续使用UTF16 - 如果你不小心所有那些隐藏的转换会让你失望。)wxWidgets库以相同的方式避免使用UTF-8,这与MAC是跨平台的。

你应该从中提取一下,并自己避免使用UTF-8。

什么时候需要使用UTF-8? UTF16的障碍在于它取决于硬件中实现的字中的字节顺序。因此,当您在不同的计算机之间传输数据(可能在其硬件中使用不同的字节顺序)时,您必须使用在任何硬件上具有相同字节顺序的UTF8。这就是浏览器和WWW页面使用UTF8的原因。

答案 6 :(得分:0)

不,如果你遵循这些指导方针就没有危险。 [1] 事实上,这是最安全,最简单的方法, [2] 即使您只为 Windows 编写。

请注意,对于欧洲语言,UTF-8 永远不会 -16>非BMP字符。对于用UTF-8中的3个字节和UTF-16中的2个编码的代码点,它只需要更多空间,这恰好是U + 0800到U + FFFF范围, [3] CJK字符。