19

C 和 POSIX 都只要求在 C/POSIX 语言环境中存在非常有限的一组字符,但允许存在其他字符。这给实施留下了很大的自由;例如,在 C 语言环境中支持所有 Unicode(如 UTF-8)是符合行为。然而,大多数历史实现都将 C 语言环境视为具有“8 位干净”单字节字符编码,即 ISO-8859-1(Latin-1)或一种“抽象 8 位字符集”,其中非 ASCII 字节是没有特定标识的抽象字符。(但是,在后一种情况下,如果编译器定义__STDC_ISO_10646__,它们通常对应于 Unicode 字符,通常是 Latin-1 范围。)

另一个似乎不太受欢迎的一致选项是将所有非 ASCII 字节视为非字符,即以EILSEQ错误响应它们。

我有兴趣知道的是在实现 C 语言环境时是否有采用此选项或任何其他不寻常选项的实现。是否存在尝试在 C 语言环境中转换“高字节”导致EILSEQ或除将它们视为(抽象或 Latin-1)单字节字符或 UTF-8 之外的任何实现?

4

4 回答 4

11

从您的评论到上一个答案:

假设可能错误的方式基本上是可移植字符集之外的字节可能是非法的非字符字节(EILSEQ)或构成一些多字节编码(UTF-8 或无状态的遗留 CJK 编码)

在这里你可以找到一个例子。

计划 9 仅支持“C”语言环境。正如您在utf.crune.c中看到的,当它在可移植字符之外找到一个 rune 时,它​​只是将其作为来自不同编码的字符处理。

另一个候选者可能是Minix*BSD 系列(就他们使用citrus而言)。在 Minix 源代码中,我还发现当字符大小不是 8 位时寻找新编码的文件命令。

于 2013-04-08T22:21:15.707 回答
5

有趣的是,我刚刚发现使用最广泛的实现 glibc 就是我正在寻找的一个示例。考虑这个简单的程序:

#include <stdlib.h>
#include <stdio.h>
int main()
{
        wchar_t wc = 0;
        int n = mbtowc(&wc, "\x80", 1);
        printf("%d %.4x\n", n, (int)wc);
}

在 glibc 上,它打印-1 0000. 如果字节 0x80 是实现的 C/POSIX 语言环境中的扩展字符,它将打印 1 后跟一些非零字符编号。

因此,关于 C/POSIX 语言环境在 glibc 上是“8 位干净”的“常识”完全是错误的。发生的事情是存在严重的不一致。尽管所有标准实用程序、正则表达式匹配等都被指定为对(多字节)字符进行操作,就好像由 读取一样mbrtowc,但这些实用程序/函数的实现在它们看到MB_CUR_MAX==1LC_CTYPE包含"C"(或类似)和直接读取值而不是使用或类似char处理输入。mbrtowc这导致了指定行为(由于定义了 C/POSIX 语言环境的实现,必须将高字节视为非法序列)和实现行为(完全绕过语言环境系统)之间的不一致。

尽管如此,我仍在寻找具有问题中要求的属性的其他实现。

于 2013-04-14T06:24:34.430 回答
4

“我有兴趣知道的是,在实现 C 语言环境时是否存在采用此选项或任何其他不寻常选项的实现。”

这个问题很难回答,因为它混合了“C 语言环境”(我假设它指的是上面提到的 C 标准限制字符集)和“其他不寻常的选项”,我假设它指的是具体的实现方式处理(有限的)C 语言环境之外的字符。每个 C 实现都必须实现 C 语言环境;我不认为有任何不寻常的选择

让我们假设问题是:“......在 C 语言环境之外实现附加/扩展字符的不寻常选项。” 现在这变成了一个依赖于实现的问题,正如您已经提到的,它“为实现留下了很大的自由度”。因此,在不知道目标编译器/硬件的情况下,仍然很难明确回答。

现在是最后一部分:

“...尝试在 C 语言环境中转换“高字节”会导致 EILSEQ 或其他任何东西,而不是将它们视为(抽象或拉丁 1)单字节字符或 UTF-8?”

而不是在 C 语言环境中转换高字节,您可以在程序中设置语言环境,就像在这个 SO 问题中一样:底层字符集是否仅依赖于 C 实现?

这样,您可以确保您的角色将在您期望的语言环境中得到处理。


据我了解,C 语言环境仅关注前 7 位(8 位char类型),基于以下来源:

术语“高字节”、“Unicode”和“UTF-8”属于多字节或宽字符编码类别,并且非常特定于语言环境(并且超出了最小 C 语言环境的范围)。我不清楚如何在(纯)C 语言环境中“转换高字节”。如果没有明确设置(或如上述链接之一所述从操作系统环境设置中提取),实现很可能会选择默认(扩展)语言环境。

于 2013-04-04T03:40:59.337 回答
2

POSIX 标准在这方面非常明确。

POSIX.1-2017 中对字符集的介绍说:

6.2 字符编码

POSIX 语言环境应包含 256 个单字节字符,包括可移植字符集和不可移植控制字符中的字符,它们具有 LC_CTYPE 中列出的属性。未指定这两个表中未列出的字符是否被分类为 punct 或 cntrl,或者两者都不是。其他语言环境应包含 Portable Character Set 中的字符,并且可能包含 Non-Portable Control Characters 中标识的任何或所有控制字符;任何附加字符的存在、含义和表示都是特定于语言环境的。

(强调我的)

mbtowc()的页面说:

如果出现以下情况,mbtowc() 函数将失败:

[EILSEQ]
 检测到无效字符序列。在 POSIX 语言环境中,不会发生 [EILSEQ] 错误,因为所有字节值都是有效字符。

请注意,POSIX 语言环境被定义为与 C 语言环境相同。

因此,如果操作系统符合 POSIX,mbtowc则在 POSIX 语言环境中是无操作的。字符 128-255 和字符 0-127 一样通过。以不同方式操作的实现违反了标准。

于 2018-04-16T12:27:59.283 回答