UTF16(例如用于宽winapi函数)字符总是2字节长吗?

时间:2011-01-10 23:03:30

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

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

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

因此,如果UTF16字符不总是2个字节长,那么它还能有多长时间? 3个字节?或只是2的倍数? 然后例如,如果有一个想要知道字符串中宽字符串大小的winapi函数,并且该字符串包含2个字符,每个字符长4个字节,那么字符串的大小如何计算?

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

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

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

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

8 个答案:

答案 0 :(得分:8)

简短回答:不。

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

此外,字符以特定于endian的格式存储。在Windows上,这通常意味着小端,但它也适用于wchar_t包含大端数据。

此外,即使每个wchar_t长度为两(或四)个字节,单个字形(粗略地说,一个字符)可能需要多个wchar_t s,并且可能有多种方式代表它。

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

简单地说,您需要知道或选择您将使用的编码。如果处理Windows API,一个简单的选择是假设所有内容都是以双字节wchar_t存储的小端UTF-16。

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

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

更新

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

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

答案 1 :(得分: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字节宽,代码点由1或2个代码单元表示。人们通常理解为“字符”的东西是不同的,可以由一个或多个代码点组成,如果你作为程序员将代码点与字符混淆,那么可能会发生诸如http://ideone.com/qV2il

之类的不良事件。

答案 2 :(得分:4)

Windows'WCHAR长16位(2字节)。

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

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

Unicode字符可能包含多个组合代码点。

答案 3 :(得分:2)

短篇小说:UTF-16是一种可变长度编码。单个字符可能是一个或两个宽字符。

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

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

答案 4 :(得分:2)

  

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

WCHAR是MS的东西,而不是C ++的东西 但是广泛的角色有一个wchar_t。虽然这并不总是2.在Linux系统上,它通常是4个字节。

  

大多数msdn和其他一些文档似乎都假设字符总是2个字节长。这可能只是我的想象力,我无法想出任何特定的例子,但它似乎就是这样。

他们。我可以相信。

  

在C ++或Windows中没有广泛使用的“超宽”函数或字符类型,因此我假设UTF16是所有需要的。

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

  

根据我不确定的知识,unicode有比65535更多的字符,所以它们显然没有2字节的足够空间。

数字0所需的2个字节 - &gt; 65535

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

  

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

UTF-8 / UTF-16和UTF-32都编码相同的代码点集(每个代码点20个字节)。 UTF-32是唯一具有固定大小的(UTF-16应该是固定大小的,但后来他们发现了我们需要编码的许多其他字符(如Klingon),我们在0平面上用完了空间。所以我们增加了32个平原(因此增加了4个位)。

  

因此,如果UTF16字符不总是2个字节长,那么它还能有多长时间? 3个字节?或只是2的倍数?

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

  

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

你必须一步一步地计算每个角色。

  

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

您系统上的所有相关人员

答案 5 :(得分:1)

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

  

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

答案 6 :(得分:1)

根据Unicode FAQ,它可能是

  

一个或两个16位代码单元

Windows使用16位字符 - 可能是因为Unicode最初是16位。所以你没有一个确切的地图 - 但是你可以通过处理你看到的只包含16个但是unicode字符的所有字符串来逃脱,

答案 7 :(得分:1)

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

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

显然,如果一个函数没有尝试检测代理对并盲目地将每对字节视为一个字符,那么它就会在包含这些字符串的字符串上出错。