【问题标题】:Are UTF16 (as used by for example wide-winapi functions) characters always 2 byte long?UTF16(例如wide-winapi函数所使用的)字符是否总是2字节长?
【发布时间】:2011-06-06 20:30:55
【问题描述】:

请为我澄清一下,UTF16 是如何工作的? 考虑到以下几点,我有点困惑:

  • C++ 中有一个静态类型,WCHAR,,长度为 2 个字节。 (显然总是 2 个字节长)(更新:如答案所示,这个假设是错误的)。
  • 大多数 msdn 和其他一些文档似乎都假设字符总是 2 个字节长。这可能只是我的想象,我想不出任何具体的例子,但似乎就是这样。
  • 在 C++ 或 Windows 中没有广泛使用的“超宽”函数或字符类型,所以我认为 UTF16 就是我们所需要的。
  • 据我所知,unicode 的字符比 65535 多得多,因此它们在 2 个字节中显然没有足够的空间。
  • UTF16 似乎是 UTF8 的更大版本,UTF8 字符可以有不同的长度。

所以如果一个 UTF16 字符并不总是 2 个字节长,它还能有多长? 3个字节?还是只有 2 的倍数? 然后例如,如果有一个 winapi 函数想知道宽字符串的大小(以字符为单位),并且该字符串包含 2 个字符,每个字符长 4 个字节,那么该字符串的大小是多少以字符为单位 em> 计算出来的?

是 2 个字符长还是 4 个字符长? (因为它是 8 个字节长,每个 WCHAR 是 2 个字节)

更新:现在我看到字符计数不一定是标准的东西或 c++ 的东西,所以我会在我的第二个问题中尝试更具体一点,关于“字符”的长度宽字符串:

在 Windows 上,特别是在 Winapi 中,在其宽函数(以 W 结尾)中,如何计算由 2 个 unicode 代码点组成的字符串中的字符数,每个代码点由 2 个代码单元组成(共 8 个字节) ?这样的字符串是 2 个字符长(与代码点数相同)还是 4 个字符长(与代码单元总数相同?)

或者,更通用:“宽字符串中的字符数”的 windows 定义是什么意思,代码点数或代码单元数?

【问题讨论】:

  • 一个 UTF-16 编码单元总是两个字节。一个 Unicode 字符可能占用 1 或 2 个代码单元。
  • 是的。 IMO UTF-16 是两全其美的:总是比 8 位编码(如 UCS-4)占用更多的空间,并且没有恒定的代码点大小(如 UTF-8)。当然,后者并不那么重要,因为组合代码点使得逻辑字符总是可以具有可变大小的表示,但前者比 UTF-8 差。
  • 好的,所以回答我的第二个问题,一个由 2 个 UTF16 字符组成的字符串,其中每个字符长 4 个字节,被所有 winapiW 函数等视为 2 个字符长?
  • 你可以阅读这篇好文章:joelonsoftware.com/articles/Unicode.html
  • @Cray:UTF-16(实际上是 UCS-2)在开发 Windows NT 时是一种方便的固定宽度编码。 Unicode 在 BMP 之外的扩展破坏了这一点。

标签: c++ winapi unicode utf-8 utf-16


【解决方案1】:

这个Wikipedia article 似乎是一个很好的介绍。

UTF-16(16 位 Unicode 转换格式)是一种 Unicode 字符编码,能够在 Unicode 代码空间中从 0 到 0x10FFFF 编码 1,112,064 个数字(称为代码点)。它为每个代码点生成一个或两个 16 位代码单元的可变长度结果。

【讨论】:

  • 这是一个很好的介绍还是看起来只是一个很好的介绍? :-)
【解决方案2】:

根据Unicode FAQ 可能是

一个或两个 16 位代码单元

Windows 使用 16 位字符 - 可能因为 Unicode 最初是 16 位的。因此,您没有确切的地图 - 但您可能能够将您看到的所有字符串视为仅包含 16 个但 unicode 字符,

【讨论】:

    【解决方案3】:

    简短的故事:UTF-16 是一种可变长度编码。单个字符可能是一两个宽字符长。

    但是,您很可能将其视为固定长度编码,其中每个字符都是一个宽字符(2 个字节)。这被正式称为 UCS-2,它曾经是 Win32 的假设,直到 Windows NT 4。UCS-2 字符集几乎包括所有活的、死的和构建的人类语言。说实话,使用可变长度编码字符串很糟糕。迭代变成 O(n) 操作,字符串长度和字符串大小不一样等等。任何合理的解析都变得很痛苦。

    至于 UCS-2 中没有的 UTF-16 字符...我只知道理论上可能在现实生活中出现的两个子集。首先是表情符号——在日本手机文化中流行的图形笑脸。在 iPhone 上,有许多第三方应用程序可以输入这些内容。除了在手机上,它们不能正常显示。另一个字符类是非常晦涩的汉字。连大多数中国人都不知道的。所有流行的汉字都在 UCS-2 中。

    【讨论】:

    • 在某些情况下超过一个码位长度的字符的一个例子是 ä,因为它有时由 ¨ 和 ä 组成
    • 这是否意味着所有 UCS-2 字符也是有效的 UTF16 字符? (UTF16 是 UCS-2 的超集)?
    • 是的。 UCS-2 仅支持 BMP(代码点 U-0000 到 U-FFFF)。 UTF-16 支持使用相同编码方案的 BMP,然后对更高的代码点使用代理对。
    • 更准确地说,UTF-16 支持 U+D800 到 U+DFFF 范围内的 BMP except,这是为代理对的特定目的而保留的。
    【解决方案4】:

    Basic Multilingual Plane 中的所有字符都是 2 个字节长。

    其他平面中的字符将被编码为每个 4 个字节,以surrogate pair 的形式。

    显然,如果一个函数不尝试检测代理对并且盲目地将每对字节视为一个字符,它将在包含此类对的字符串上出错。

    【讨论】:

    • 确实如此,但你遇到来自更高位面的角色的可能性有多大?
    • @Seva:取决于您住在哪里以及与谁做生意。或者,更重要的是,您的客户与谁做生意。
    • 还有你对字符串做了什么。如果只是存储和显示,那么它几乎从来都不是问题,除非您尝试从字符数中确定可见的字符串长度(由于其他原因,这也是一个坏主意)。然而,出于解析目的......根据解析的性质,它可能会变成一堆蠕虫。
    【解决方案5】:

    你似乎有几个误解。

    C++中有一个静态类型,WCHAR,长度为2字节。 (显然总是 2 个字节长)

    这是错误的。假设您引用 c++ 类型 wchar_t - 它并不总是 2 个字节长,4 个字节也是一个常见值,并且没有限制它只能是这两个值。如果您不提及它,则它不是 C++ 中的,而是某些特定于平台的类型。

    • 在 C++ 或 Windows 中没有广泛使用的“超宽”函数或字符类型,所以我认为 UTF16 就是我们所需要的全部。

    • UTF16 似乎是 UTF8 的更大版本,UTF8 字符可以有不同的长度。

    UTF-8 和 UTF-16 是同一字符集的不同编码,因此 UTF-16 并不“更大”。从技术上讲,UTF-8 中使用的方案可以编码比 UTF-16 中使用的方案更多的字​​符,但作为 UTF-8 和 UTF-16,它们编码相同的集合。

    在涉及 unicode 时,不要轻易使用“字符”一词。 UTF-16 中的 codeunit 为 2 个字节宽,codepoint 由 1 或 2 个 codeunits 表示。人们通常理解为“字符”的东西是不同的,可以由一个或多个代码点组成,如果您作为程序员将代码点与字符混淆,则可能会发生类似http://ideone.com/qV2il

    【讨论】:

    • 我特别指的是术语“字符”,因为它例如在 Winapi 函数中使用。他们都写了诸如“字符串的字符大小”之类的东西。但感谢您澄清代码点和代码单元。
    • 在 RFC 2044 和 2279 中定义的原始 UTF-8 规范最多支持 6 个代码单元(U-0000 到 U+7FFFFFFF)。然而,为了与 UTF-16 的互操作性,RFC 3629(现在被 Unicode 本身采用)将 UTF-8 限制为最多 4 个代码单元,因此它使用 UTF-16 支持的相同范围的代码点(U-0000 到 U+1FFFFF) .这使得两者更兼容无损转换。
    • @TeamB:你为什么要告诉我一些我知道的事情?
    【解决方案6】:

    Windows 的WCHAR 长度为 16 位(2 字节)。

    一个 Unicode 代码点可以由这些 WCHAR 中的一个或两个表示 - 16 或 32 位(2 或 4 个字节)。

    wcslen 返回宽字符串中WCHAR 单位的数量,而wcslen_l 返回(取决于区域设置的)代码点的数量。显然,wcslen <= wcslen_l

    一个 Unicode 字符可能由多个组合代码点组成。

    【讨论】:

    • 谢谢!但是,您不是说最后一句话中的代码单元(不是代码点)(如 etarion 的回答中所述)吗?否则你的解释意味着一个unicode字符可以用4个以上的字节表示,你是这个意思吗?
    • @Cray:是的,我就是这个意思。一个 Unicode 字形(你认为是一个字符)可以由多个组合代码点组成;一个 Unicode 代码点可以由一个或两个 UTF-16 单元组成。
    【解决方案7】:

    C++中有一个静态类型,WCHAR,长度为2字节。 (显然总是 2 个字节长)

    WCHAR 是 MS 的东西,而不是 C++ 的东西。
    但是有一个 wchar_t 用于宽字符。虽然这并不总是 2。在 Linux 系统上它通常是 4 字节。

    大多数 msdn 和其他一些文档似乎都假设字符总是 2 个字节长。这只是我的想象,我想不出任何具体的例子,但似乎就是这样。

    他们。我可以相信。

    在 C++ 或 Windows 中没有广泛使用的“超宽”函数或字符类型,所以我认为 UTF16 就是我们所需要的全部。

    C/C++ 不对字符编码做任何假设。虽然操作系统可以。例如,Windows 使用 UTF-16 作为接口,而许多 Linus 使用 UTF-32。但是你需要阅读每个接口的文档才能明确知道。

    据我所知,unicode 的字符比 65535 多得多,因此它们显然在 2 个字节中没有足够的空间。

    数字 0 -> 65535 只需要 2 个字节

    但 UCS(UTF 所基于的编码)每个代码点有 20 位。因此,一些代码点被编码为 UTF-16 中的 2 个 16 字节字符(这些被称为代理对)。

    UTF16 似乎是 UTF8 的更大版本,UTF8 字符可以有不同的长度。

    UTF-8/UTF-16 和 UTF-32 都对同一组代码点进行编码(每个代码点 20 个字节)。 UTF-32 是唯一一个具有固定大小的字符(UTF-16 应该是固定大小的,但后来他们发现了许多其他字符(如克林贡语)需要我们编码,因此我们在 0 平面上的空间不足。所以我们增加了 32 个平原(因此增加了 4 个额外的位)。

    所以如果一个 UTF16 字符并不总是 2 个字节长,它还能有多长? 3个字节?还是只有 2 的倍数?

    它是 1 个 16 位字符或 2 个 16 位字符。

    然后例如,如果有一个 winapi 函数想知道一个宽字符串的大小(以字符为单位),并且该字符串包含 2 个字符,每个字符长 4 个字节,那么该字符串的字符大小是如何计算的?

    你必须一步一步计算每个字符。

    是 2 个字符长还是 4 个字符长? (因为它是 8 个字节长,每个 WCHAR 是 2 个字节)

    所有依赖于您的系统

    【讨论】:

    • 您误解了我的问题中的几个小点,但总而言之,这是一个很好的解释,谢谢!我仍然不确定长度如何取决于系统......
    【解决方案8】:

    简短回答:不。

    wchar_t(基本字符单元)的大小未由 C++ 标准定义(请参阅第 3.9.1 节第 5 段)。实际上,在 Windows 平台上它是两个字节长,而在 Linux/Mac 平台上它是四个字节长。

    此外,字符以特定于字节序的格式存储。在 Windows 上,这通常意味着小端,但 wchar_t 包含大端数据也是有效的。

    此外,即使每个wchar_t 有两个(或四个)字节长,一个单独的字形(大致是一个字符)可能需要多个wchar_ts,并且可能有不止一种表示它的方法。

    一个常见的例子是字符 é (LATIN SMALL LETTER E WITH ACUTE),代码点 0x00E9。这也可以表示为“分解”的代码点序列 0x0065 0x0301(即LATIN SMALL LETTER E 后跟COMBINING ACUTE ACCENT)。两者都有效;有关更多信息,请参阅Unicode equivalence 上的维基百科文章。

    简单地说,您需要知道或选择您将使用的编码。如果处理 Windows API,一个简单的选择是假设所有内容都是 little-endian UTF-16 存储在 2 字节 wchar_ts 中。

    在 Linux/Mac 上,UTF-8(带有chars)更常见,API 通常采用 UTF-8。 wchar_t 被视为浪费,因为它每个字符使用 4 个字节。

    因此,对于跨平台编程,您可能希望在内部使用 UTF-8 并在调用 Windows API 时即时转换为 UTF-16。 Windows 提供了MultiByteToWideCharWideCharToMultiByte 函数来执行此操作,您还可以找到简化使用这些函数的包装器,例如ATL and MFC String Conversion Macros

    更新

    该问题已更新为询问 Windows API 在询问字符串中的“字符数”时的含义。

    如果 API 说“以字符为单位的字符串大小”,则它们指的是 wchar_ts 的数量(或者,如果您出于某种原因在非 Unicode 模式下编译,则为 chars 的数量)。在特定情况中,您可以忽略一个 Unicode 字符可能包含多个 wchar_t 的事实。这些 API 只是想填充缓冲区,需要知道它们有多少空间。

    【讨论】:

      猜你喜欢
      • 2011-06-26
      • 2023-04-02
      • 2018-12-16
      • 2015-08-03
      • 2011-08-24
      • 1970-01-01
      • 1970-01-01
      • 2022-01-07
      相关资源
      最近更新 更多