gpt4 book ai didi

c - 为什么 Mac OS 上的 C 运行时允许预组合和分解的 UTF-8?

转载 作者:行者123 更新时间:2023-12-04 12:19:16 25 4
gpt4 key购买 nike

所以我们都知道 Mac OS 上的文件系统具有使用完全分解的 UTF-8 的古怪功能。例如,如果您调用 realpath() 之类的 POSIX API,您将从 Mac OS 返回完全分解的 UTF-8 字符串。但是,当使用像 fopen() 这样的 API 时,传递预组合的 UTF-8 似乎也能正常工作。

这是一个小的演示程序,它试图打开一个名为 ä 的文件。对 fopen() 的第一次调用传递了一个预组合的 UTF-8 字符串,第二次调用传递了一个分解的 UTF-8 字符串,令我惊讶的是两者都有效。我希望只有第二个可以工作,但预组合的 UTF-8 也可以。

#include <stdio.h>

int main(int argc, char *argv[])
{
FILE *fp, *fp2;

fp = fopen("\xc3\xa4", "rb"); // ä as precomposed UTF-8
fp2 = fopen("\x61\xcc\x88", "rb"); // ä as decomposed UTF-8

printf("CHECK: %p %p\n", fp, fp2);

if(fp) fclose(fp);
if(fp2) fclose(fp2);

return 0;
}

现在回答我的问题:

  1. 这是定义的行为吗?即是否允许将预组合的 UTF-8 传递给 POSIX API,还是我应该始终传递分解的 UTF-8?

  2. fopen() 之类的函数如何知道传递的文件是否包含预合成或分解的 UTF-8?这难道不会导致各种问题,例如因为传递的字符串可以用两种不同的方式解释并因此可能指向两个不同的文件,所以打开了错误的文件?这让我有些困惑。

编辑

为了使混淆更加彻底,这种奇怪的行为似乎并不局限于文件 I/O。看看这段代码:

#include <stdio.h>

int main(int argc, char *argv[])
{
printf("\xc3\xa4\n");
printf("\x61\xcc\x88\n");

return 0;
}

两个 printf 调用完全相同,即它们都打印字符 ä,第一个调用使用预组合的 UTF-8,第二个调用使用分解的 UTF-8 .这真的很奇怪。

最佳答案

Unicode 字符串中有两种不同类型的等价:一种是规范等价,另一种是兼容性。由于您的问题是关于软件似乎认为相同的字符串,因此让我们关注规范等价(OTOH,兼容性允许语义差异,因此它离题了这个问题)。

引自 Unicode equivalence在维基百科中:

Code point sequences that are defined as canonically equivalent are assumed to have the same appearance and meaning when printed or displayed. For example, the code point U+006E (the Latin lowercase "n") followed by U+0303 (the combining tilde "◌̃") is defined by Unicode to be canonically equivalent to the single code point U+00F1 (the lowercase letter "ñ" of the Spanish alphabet). Therefore, those sequences should be displayed in the same manner, should be treated in the same way by applications such as alphabetizing names or searching, and may be substituted for each other.

换句话说,如果两个字符串规范等价,软件应该认为这两个字符串代表完全相同的东西。所以,MacOS 在这里做了正确的事情:你有两个不同的 UTF-8 字符串(一个分解,另一个预组合),但它们是规范等价的,所以它们映射到同一个对象(同一个文件)在你的例子中的名字)。这是正确的(记住上面引述中的“应用程序应该以相同的方式处理名称或搜索等,并且可以相互替换”)。

我不太理解你关于 printf() 的第二个例子。是的,分解字符和预合成字符呈现相同的输出。这正是 Unicode 支持的字符双重表示的要点:您可以选择是用预先组合的字节序列表示组合字符,还是用分解的字节序列表示。它们打印出相同的视觉结果,但它们的表现形式不同。如果两种表示都是规范等价的(在某些情况下它们是,在某些情况下它们不是),那么系统必须将它们视为同一对象的两种表示。

为了在您的软件中更舒适地管理所有这些,您应该 normalize your Unicode strings在与他们合作之前。

关于c - 为什么 Mac OS 上的 C 运行时允许预组合和分解的 UTF-8?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38484369/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com