glibc 的 isalpha 函数和 en_US.UTF-8 语言环境

时间:2020-12-30 23:37:04

标签: c locale glibc utf

简短版本:当语言环境设置为除 isalpha 以外的其他内容(换句话说,类似于 C)时,C 函数 en_US.UTF-8 如何工作?

长版:在阅读一堆关于 isalpha 函数的文档时,我不是 100% 清楚它的语言环境相关行为是如何工作的。具体来说,我找到了文档 that say things like

<块引用>

在某些语言环境中,可能会有额外的 isalpha 为真的字符——既不是大写也不是小写的字母。但是在标准的“C”语言环境中,没有这样的附加字符。

此外——如果我用一个小的 C 程序测试这个,我可以确认 isalpha 将返回 true/1 对于传统 ASCII 文本范围之外的值,当设置了不同的语言环境——对于某些unix。这个程序在我基于 BSD/Darwin 的 mac 上似乎做的很合理——但是当我在 ubuntu 机器上尝试它时它出现了段错误。

    #include <stdio.h>
    #include <ctype.h>
    #include <locale.h>
    #include <limits.h>
    int main() {
        setlocale(LC_ALL, "en_US.UTF-8");
        for(int i=0;i<INT_MAX;i++) {
           // printf() displays the string inside quotation
            if(isalpha(i)) {
                printf("is alpha numeric: %i\n", i);
            }

        }
       return 0;
    }

我不清楚的是,当语言环境设置为 isalpha 时,en_US.UTF-8 如何知道哪些整数应该返回 true 以及这些整数代表什么。这只是某个范围内的 utf 代码点的硬编码列表吗?或者不那么直接的东西?

我自己尝试过解决这个问题,但我的鸽子-c 无法胜任。

我已经达到了 ctype.cctype.h。如果我深入研究 glibc 的源代码,我会发现 isalpha 函数是 actually a macro,它扩展为类似这样的内容

int isalpha (int c) {
    return __isctype (c, _ISalpha);
}

__isctype is also a macro,因此我们将其扩展为类似

int isalpha (int c) {
    return ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) _ISalpha) (c, _ISalpha);
}

还有 _ISalpha enum expands out 到一个小端位掩码,所以现在我们正在研究这样的东西......

int isalpha (int c) {
    return ((*__ctype_b_loc ())[(int) (c)] & (unsigned short int) ((2) < 8 ? ((1 << (2)) << 8) : ((1 << (2)) >> 8))) (c, ((2) < 8 ? ((1 << (2)) << 8) : ((1 << (2)) >> 8)));
}

这就是我挖掘的地方。

除了了解 isalpha 的工作原理外,我没有特别的目标。

1 个答案:

答案 0 :(得分:3)

<块引用>

当语言环境设置为 C 以外的其他内容(换句话说,类似于 en_US.UTF-8)时,C 函数 isalpha 如何工作?

Unicode 的前 128 个字符表示与 ASCII 相同,因此没有任何变化(当 C 语言环境使用 ASCII 时)。

真正改变的是,glibc 不再使用硬编码列表,而是打开并加载语言环境文件。我相信这将来自 /usr/lib/locale/locale-archive,它应该包含来自 /usr/share/i18n/locales/* 文件的编译语言环境。在我的 /usr/share/i18n/locales/en_US 文件中,我看到 LC_CTYPE copy "en_GB" ,我可以去 en_GBcopy "i18n",然后到 i18ncopy "i18n_ctype",最后到 i18n_ctype 文件,其中包含:

% The "alpha" class of the "i18n" FDCC-set is reflecting
% the recommendations in TR 10176 annex A
alpha /
   <U0041>..<U005A>;<U0061>..<U007A>;<U00AA>;<U00B5>;<U00BA>;/
   <U00C0>..<U00D6>;<U00D8>..<U00F6>;<U00F8>..<U02C1>;<U02C6>..<U02D1>;/
.... many more lines ....
<块引用>

我可以确认 isalpha 将为传统 ASCII 文本范围之外的值返回 true/1

来自C99 7.4p1

<块引用>

在所有情况下,参数都是 int,其值应表示为无符号字符或应等于宏 EOF 的值。如果参数有任何其他值,则行为未定义。

循环:for(int i=0;i<INT_MAX;i++) { if(isalpha(i)) { 只是任何 i 大于 UCHAR_MAX 的未定义行为。有些程序员甚至会做isalpha((unsigned char)i)。 (我记得在某些情况下当 is<ctype>(arg) 函数参数不是无符号字符时收到警告)。

<块引用>

这只是某个范围内的 utf 代码点的硬编码列表吗?或者不那么直接的东西?

是的,如上文 /usr/share/i18n/locales/* 文件中所述。

C 语言环境的硬编码列表存储在 locale/C-ctype.c 中,旨在匹配 POSIX

相关问题