Windows API:ANSI和宽字符字符串——是UTF8还是ASCII?UTF-16还是UCS-2 LE?

39
我对编码并不是很精通,但这是我所知道的(可能有误):
  1. ASCII 是一种7位固定长度的编码,包含在 ASCII 表中的字符。
  2. UTF8 是一种8位可变长度的编码,所有字符均可用 UTF8 编写。
  3. UCS-2 LE/BE 是固定长度的16位编码,支持大多数常见字符。
  4. UTF-16 是一种16位可变长度的编码,所有字符均可用 UTF16 编写。
以上内容正确吗?
现在是问题时间:
  1. Windows 的“ A”函数(如 SetWindowTextA)接受 ASCII 字符串还是“多字节字符串”(下面会有更多关于此的问题)?
  2. Windows 的“ W”函数接受 UTF-16 字符串还是 UCS-2 字符串?我认为它们接受 UCS-2,但名称使我感到困惑。
  3. WideCharToMultiByte 中,Microsoft 使用“宽字符字符串”这个词表示 UTF-16。在这种情况下,“多字节字符串”指什么?UTF-8 吗?
  4. LPWSTR 是“宽字符字符串”吗?我认为是,但那不意味着它是 UTF-16 吗?那不是意味着它可以用于显示例如4字节的字符吗?如果不是,则显示4字节字符是否不可能?(Windows 似乎没有针对这些字符的 API。)
  5. WideCharToMultiByte 的功能是否包含在 wcstombs 中,并且它们都使用相同类型的字符串?还是说其中一个使用 UTF-16,而另一个使用 UCS-2?
  6. 文件路径采用 UTF-16 还是 UCS-2?我知道 Windows 将其视为“不透明的字符数组”(根据 Microsoft 的文档),但根据 C 标准,例如 fwprintf 等函数,是否存在标准化的编码?
  7. “ANSI”编码是什么?那是正确的术语吗?它与 ASCII 有什么关系?
  8. (我有更多问题,但这就够了……我也忘记了其中一些……)
这是很多问题,因此任何关于它们如何连接的解释的链接(除了阅读 Unicode 标准,这对 Windows API 没有帮助)也将不胜感激。
谢谢!

1
为什么Unicode标准不能帮助Windows?据我所知,我推荐的参考书是O'Reilly出版的这本书:http://oreilly.com/catalog/9780596101213/ - David Heffernan
1
@David:因为它无法回答有关A和W函数的问题。但感谢您提供这本书的参考,它似乎很有趣。 - user541686
2
这是一本好书。了解Unicode的一般背景确实有助于理解具体内容,特别是您将更清楚地了解为什么Windows API是这样的。 - David Heffernan
4个回答

31
这些都是正确的吗?
是的,如果您不假设Unicode编码中不存在未编码的字符(对于大多数实际应用程序而言,这种假设是可以的)。
Windows 的"A"函数(例如SetWindowTextA)接受ASCII字符串吗?还是接受"多字节字符串"(下面还有更多问题)?
它们接受字节字符串(即其代码单元为字节的字符串,在Windows上始终是八位字节),这些字符串以当前的"ANSI"/MBCS/legacy编码进行编码。 "ANSI"是这些编码的历史术语,但并不正确。对于西方Windows系统,该编码通常为Windows-1252。
Windows 的"W"函数接受UTF-16字符串还是UCS-2字符串?我认为它们接受UCS-2,但名称让我感到困惑。
自Windows 2000以来,它们大多数支持UTF-16。选择"wide"和Microsoft术语的其余部分(例如,"Unicode"表示"UTF-16"或"UCS")是在现代Unicode标准统一术语之前的。
在WideCharToMultiByte中,Microsoft使用"wide-character string"这个词来表示UTF-16。那么什么被认为是"multi-byte string"? UTF-8?
在这个上下文中,WideCharToMultiByte支持的其他所有编码都是"多字节编码",包括Windows-1251和UTF-8。
LPWSTR是"宽字符字符串"吗?我会这样说,但那不是意味着它是UTF-16吗?那不是意味着它可以用于显示,例如4字节字符吗?如果不是,那么...显示4字节字符是不可能的吗?(Windows似乎没有针对这些的API。)

LPWSTR是指向wchar_t的指针,在Windows上wchar_t始终是一个16位无符号整数。可以显示哪些字符与编码无关,只要该编码能够编码所有Unicode字符。Windows通常可以显示非BMP字符,但不是在所有地方(例如控制台不能)。

WideCharToMultiByte的功能是否是wcstombs的超集,并且它们两者都适用于同一类型的字符串?或者其中一个适用于UTF-16,而另一个适用于UCS-2?

不是很确定,但我认为它们之间的区别不大。我想你只需要尝试将一些非BMP字符转换为UTF-8,并查看结果是否正确。

文件路径是UTF-16还是UCS-2?我知道Windows将其视为Microsoft文档中的“不透明字符数组”,但对于类似fwprintf的C标准函数,是否有任何标准化的编码方式?

文件路径确实是不透明的UTF-16字符数组,这意味着Windows在存储或读取文件名时不执行任何形式的转换(类似Linux,不像Mac OS X)。但Windows仍然有其奇怪的主要未定义的不区分大小写行为,这会引起许多麻烦,因为被视为等价的文件名并不一定相等。这打破了很多不变量;例如,在Linux上,如果您在某个目录中成功创建两个文件A和a而没有其他线程干扰,则最终会得到两个不同的文件,而在Windows上只有一个文件(通常是不可预测的文件数量)。

“ANSI”编码是什么?那是正确的术语吗?它与ASCII有何关系?

“ANSI”编码是指使用单字节字符集的编码,例如Windows上的CP1252或ISO-8859-1。但是,这个术语是不正确的,因为它不能明确地描述特定的编码。ASCII是一个较小的字符集,只包含128个字符,其中包括英文字母、数字和一些标点符号。

ANSI是美国标准化组织。在提到编码时使用这个词是一个错误的用法,但却很常见,因此您应该意识到这一点。我更喜欢使用术语“传统的8位编码”,因为我认为这基本上就是它的定义:一种非Unicode编码,仅为了与传统(Windows 9x)应用程序兼容而保留。在西方系统中,通常使用的是Windows-1252编码,它是ASCII的一个适当超集。


2
大小写敏感是文件系统的一个属性。在NTFS中,它由存储在隐藏文件中的小写到大写映射定义,该文件在格式化文件系统时创建。因此,它可能会因文件系统格式化时所使用的语言环境而略有不同。 - Ben

8
  1. *A函数使用活动的ANSI代码页。

  2. *W函数使用UTF-16。

  3. 多字节是指传递给CodePage参数的任何内容。最常见的是活动的ANSI代码页或UTF-8。

  4. LPWSTR是一个UTF-16字符串,可能有或没有以null结尾(参见MSDN

  5. 我不知道wcstombs的任何信息,我总是使用WideCharToMultiByte。

  6. 文件路径是UTF-16格式。实际上,在Windows中所有文本都是内部使用UTF-16。

  7. 对于ANSI编码,您需要详细了解。您可以从维基百科开始,然后从那里跟随链接。

我希望这可以帮助你,如果我有任何错误,请知道更多的人进行编辑以纠正任何错误!


8

宽字符串曾经使用的是UCS-2编码。从Windows 2000开始,宽字符串采用UTF-16编码。如果需要维护一些旧的遗留系统,这一点非常重要。


2
首先,在这个SO主题中,您会找到大量关于此问题的信息。
ASCII是字符集而非编码。现在有许多8位字符集,其中一个被设置为系统默认值(您可以在区域设置中更改)。*A函数接受该字符集中的8位字符。UTF-8不是字符集,而是Unicode字符集的编码。*W函数使用的是UTF-16而非UCS-2,据我所知。

非常感谢您提供的链接!但有一件事让我困惑:如果*W函数是UTF-16编码,那么为什么微软会说“文件系统将路径和文件名视为不透明的WCHARs序列”?(http://msdn.microsoft.com/en-us/library/aa365247%28v=vs.85%29.aspx) - user541686
1
@Lambert,这个语句有什么问题吗?它意味着Windows不会对传递的文件名进行任何解释,即使包含代理字符,Windows也不会关心它们。我认为Unicode专家能够更好地解释。 - Eugene Mayevski 'Callback
1
这并不是真正的问题--问题在于,这意味着您可以传递无效的非Unicode数据,而它仍然可以工作。这正确吗? - user541686
2
@Lambert 是的,有点像。Windows会接受除了\0和禁止字符(斜杠、引号、问号和星号)之外的任何内容。这正是他们在那里所说的 - Windows不关心传递的Unicode字符的有效性。 - Eugene Mayevski 'Callback

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接