Windows API:ANSI 和宽字符字符串——是 UTF8 还是 ASCII? UTF-16 还是 UCS-2 LE?
Posted
技术标签:
【中文标题】Windows API:ANSI 和宽字符字符串——是 UTF8 还是 ASCII? UTF-16 还是 UCS-2 LE?【英文标题】:Windows API: ANSI and Wide-Character Strings -- Is it UTF8 or ASCII? UTF-16 or UCS-2 LE? 【发布时间】:2011-06-03 07:08:59 【问题描述】:我不太擅长编码,但这是我认为我知道的(尽管它可能是错误的):
-
ASCII 是一种 7 位、固定长度的编码,您可以在 ASCII 图表中找到字符。
UTF8 是一种 8 位可变长度编码。所有字符都可以用 UTF8 书写。
UCS-2 LE/BE 是固定长度的 16 位编码,支持最常见的字符。
UTF-16 是一种 16 位的可变长度编码。所有字符都可以用 UTF16 书写。
这些都是正确的吗?
现在,对于问题:
-
Windows“A”函数(如
SetWindowTextA
)是否接收ASCII 字符串?还是“多字节字符串”(下面有更多问题)?
Windows 的“W”函数接受 UTF-16 字符串还是 UCS-2 字符串?我以为他们接受 UCS-2,但名字让我很困惑。
在WideCharToMultiByte 中,Microsoft 使用“宽字符串”一词来表示 UTF-16。在这种情况下,什么被认为是“多字节字符串”? UTF-8?
LPWSTR
是“宽字符串”吗?我会说它是,但是,那不是意味着它是 UTF-16 吗?这不是说它可以用来显示,比如说,4 字节的字符吗?如果不是,那么...显示 4 字节字符是不可能的吗? (Windows 似乎没有这些 API。)
WideCharToMultiByte
的功能是否是wcstombs
的超集,它们是否都适用于相同类型的字符串?或者说,一个在 UTF-16 上工作,而另一个在 UCS-2 上工作?
文件路径是 UTF-16 还是 UCS-2?我知道 Windows 将其视为 Microsoft 文档中的“不透明字符数组”,但根据 fwprintf
等函数的 C 标准,是否有任何标准化编码?
什么是“ANSI”编码?这甚至是一个正确的术语吗?它与 ASCII 有什么关系?
(我还有更多问题,但这已经足够了……反正我忘记了一些……)
这些问题很多,因此任何关于所有这些如何连接的解释链接(除了阅读 Unicode 标准,这对 Windows API 没有帮助)也将不胜感激。
谢谢!
【问题讨论】:
为什么 Unicode 标准对 Windows 没有帮助?我首选的参考资料是 O'Reilly 的书:oreilly.com/catalog/9780596101213 @David:因为它无法回答有关 A 与 W 函数的问题。不过感谢您对这本书的参考,它似乎很有趣。 这是一本好书。了解更多关于 Unicode 的一般背景有助于理解细节,尤其是您将更清楚地了解 Windows API 为何如此。 【参考方案1】:这些都是正确的吗?
是的,如果您不假设存在未以 Unicode 编码的字符(对于大多数实际应用,这个假设很好)。
Windows“A”函数(如 SetWindowTextA)是否接收 ASCII 字符串?还是“多字节字符串”(下面有更多问题)?
它们采用以当前“ANSI”/MBCS/legacy 编码方式编码的字节字符串(即代码单元为字节的字符串,在 Windows 上始终为八位字节)。 “ANSI”是这些编码的历史术语,但不正确。对于西方 Windows 系统,这种编码通常是 Windows-1252。
Windows 的“W”函数接受 UTF-16 字符串还是 UCS-2 字符串?我以为他们接受 UCS-2,但名字让我感到困惑。
从 Windows 2000 开始,大部分都支持 UTF-16。在现代 Unicode 标准统一术语之前,选择了名称“wide”和其他 Microsoft 术语(例如,“Unicode”表示“UTF-16”或“UCS”)。
在 WideCharToMultiByte 中,Microsoft 使用“宽字符串”一词来表示 UTF-16。在这种情况下,什么被认为是“多字节字符串”? UTF-8?
WideCharToMultiByte
支持的所有其他编码在此上下文中都是“多字节编码”,包括 Windows-1251 和 UTF-8。
LPWSTR 是“宽字符串”吗?我会说它是,但是,那不是意味着它是 UTF-16 吗?这是否意味着它可以用来显示,比如说,4 字节字符?如果不是,那么...显示 4 字节字符是不可能的吗? (Windows 似乎没有这些 API。)
LPWSTR
是一个指向 wchar_t
的指针,在 Windows 上它始终是一个 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 是美国标准化组织。在提到编码时使用这个词是用词不当,但经常使用,因此您应该注意它。我更喜欢术语旧版 8 位编码,因为我认为它本质上就是这样:一种非 Unicode 编码,仅为了与旧版 (Windows 9x) 应用程序兼容而保留。在西方系统上,这通常是 Windows-1252,它是 ASCII 的正确超集。
【讨论】:
区分大小写是文件系统的一个属性。在 NTFS 中,它由存储在隐藏文件中的从小写到大写的映射定义,该隐藏文件是在格式化文件系统时创建的。因此,它可能会(略微)有所不同,具体取决于文件系统格式化的语言环境。【参考方案2】:*A 函数使用了活动的 ANSI 代码页。
*W 函数使用 UTF-16。
多字节是指在 CodePage 参数中传递的任何内容。它最常见的是活动的 ANSI 代码页或 UTF-8。
LPWSTR 是一个 UTF-16 字符串,它可能会或可能不会以 null 结尾(请参阅 MSDN)
我对 wcstombs 一无所知,我总是使用 WideCharToMultiByte。
文件路径采用 UTF-16 格式。事实上,Windows 内部的所有文本都是 UTF-16。
对于 ANSI 编码,您需要详细阅读它。您可能比从Wikipedia 开始并点击那里的链接更糟糕。
我希望对您有所帮助,如果我有任何错误,请知道更多信息的任何人编辑此内容以更正任何错误!
【讨论】:
【参考方案3】:宽字符串曾经是 UCS-2。从 Windows 2000 开始,宽字符串是 UTF-16。很高兴知道您是否需要维护一些旧的遗留系统。
【讨论】:
【参考方案4】:首先,您会在this SO topic 中找到大量信息。
ASCII 是字符集,不是编码。现在,有许多 8 位字符集,其中一个在系统中被设置为默认值(您可以在区域设置中更改它)。 *A 函数接受该字符集中的 8 位字符。 UTF-8 不是字符集,而是 Unicode 字符集的编码。 *W 函数,据我所知,使用 UTF-16 而不是 UCS-2。
【讨论】:
非常感谢您的链接!不过,让我感到困惑的是:如果 *W 函数是 UTF-16,那么微软怎么会说,"the file system treats path and file names as an opaque sequence of WCHARs"? @Lambert 这个声明有什么问题?这意味着 Windows 不会对传递的文件名执行任何解释,即如果包含代理字符,则 Windows 不关心它们。我认为 Unicode 专家将能够解释更多。 这不是真正的问题——问题是,这意味着你可以传入无效的非 Unicode 数据,它仍然可以工作。对吗? @Lambert 是的,有点。 Windows 将接受除 \0 和禁止字符(斜线、引号、问题和星号)以外的任何字符。这正是他们在那里所说的 - Windows 不关心传递的 unicode 字符的有效性。以上是关于Windows API:ANSI 和宽字符字符串——是 UTF8 还是 ASCII? UTF-16 还是 UCS-2 LE?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 unicode 版本的 Windows API:mciSendString()、Python
Windows 记事本的 ANSI,Unicode,UTF-8 这三种编码模式有啥区别
Windows核心编程之核心总结(第二章 字符和字符串处理)(2018.5.27)