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 上,如果您在某个目录中成功创建了两个文件 Aa,您最终会得到两个不同的文件,而在 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?的主要内容,如果未能解决你的问题,请参考以下文章

c_cpp 将ANSI字符输出到Windows控制台

如何使用 unicode 版本的 Windows API:mciSendString()、Python

Windows 记事本的 ANSI,Unicode,UTF-8 这三种编码模式有啥区别

Windows核心编程之核心总结(第二章 字符和字符串处理)(2018.5.27)

Windows Internals 笔记——字符和字符串处理

Windows核心编程第二章,字符串的表示以及宽窄字符的转换