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

glibc's isalpha function and the en_US.UTF-8 locale

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

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

In some locales, there may be additional characters for which isalpha is true--letters which are neither upper case nor lower case. But in the standard "C" locale, there are no such additional characters.

此外——如果我用一个小的 C 程序对此进行测试,我可以确认 isalpha 将 return 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;
    }

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

我试着自己解决这个问题,但我的 pigeon-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 的工作原理外,我没有特别的目标。

How does the C function isalpha work when the locale is set to something other than C (in other words, something like en_US.UTF-8)?

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" ,我可以转到具有 copy "i18n"en_GB,然后转到具有 copy "i18n_ctype"i18n,最后至 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 ....

I can confirm that isalpha will return true/1 for values outside of the traditional ASCII text ranges

来自 C99 7.4p1:

In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.

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

Is this just a hard coded list of utf code points in a range somewhere? Or something less direct?

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

并且 C 语言环境的硬编码列表存储在 locale/C-ctype.c and is meant to match POSIX