为啥 wctype.h 中的函数在没有 setlocale() 的情况下不起作用?

Posted

技术标签:

【中文标题】为啥 wctype.h 中的函数在没有 setlocale() 的情况下不起作用?【英文标题】:Why functions from wctype.h do not work without setlocale()?为什么 wctype.h 中的函数在没有 setlocale() 的情况下不起作用? 【发布时间】:2017-03-22 20:59:47 【问题描述】:

我的设置:glibc 2.24、gcc 6.2.0、UTF-8 环境。

考虑以下示例:

#include <wchar.h>
#include <wctype.h>
#include <locale.h>
int main(void)

  setlocale(LC_CTYPE, "en_US.UTF-8");
  wchar_t wc = L'я'; /* 00000100 01001111 */
  if (iswlower(wc)) return 0;
  return 1;

编译并运行它:

$ gcc test.c
$ ./a.out; echo $?
0

现在删除setlocale() 并再次运行。结果不一样:

$ gcc test.c
$ ./a.out; echo $?
1

从技术上讲,这里不需要setlocale(),因为wctype.h 中的函数使用具有固定编码的宽字符。 (不用说,如果我们希望 ctype.h 中的函数能够正确处理非 ASCII 字符,并且如果我们使用 wchar.h 中的字符转换函数 - 设置外部编码,则需要 setlocale()。)

为什么没有setlocale(),这个例子就不能工作?

【问题讨论】:

它怎么知道使用哪个字母? @IgnacioVazquez-Abrams ISO10646 - 对于宽字符是固定的。 gnu.org/software/libc/manual/html_node/Extended-Char-Intro.html ISO 10646 没有命名字母表。 @IgnacioVazquez-Abrams 你有没有注意到我使用了en_US.UTF-8,但是符号я 不是来自en_US,它被正确分类了。所以,不,ISO10646 确实命名了字母表。 它不是 en_US 字母表的一部分,但它确实具有该语言的定义排序规则。 【参考方案1】:

C 标准说:

7.25 宽字符分类和映射实用程序&lt;wctype.h&gt;

...

这些函数的行为受当前语言环境的LC_CTYPE 类别影响。

此外(5.2.1 字符集)

应定义两组字符及其相关的整理顺序: 写入了哪些源文件(源字符集),以及在 执行环境(执行字符集)。每组又分为一个 基本字符集,其内容由本子条款给出,以及一组零个或多个 特定于语言环境的成员(不是基本字符集的成员)称为 扩展字符。

然后(7.19 常用定义&lt;stddef.h&gt;

wchar_t 这是一个整数类型,其值范围可以表示在支持的语言环境中指定的最大扩展字符集

的所有成员的不同代码

因此可能有许多扩展字符集,每个语言环境一个。因此,wchar_t 编码可能依赖于语言环境,因为编码是一组整数代码和一组字符之间的映射,而后者可能是依赖于语言环境的。

鉴于上述情况,&lt;wctype.h&gt; 必须依赖于区域设置。否则,标准将不得不强制要求有一个独立于语言环境的扩展字符集。

在这个特定的例子中,宽字符常量L'я'(一些整数代码)的值可能对应于C语言环境下扩展字符集的任何成员,也可能不对应。

至于 gcc 和 glibc 的特定行为,为了简单起见,它们总是使用 Unicode/ISO10646/UCS4 作为扩展字符集,在任何语言环境下。但是,它们不会在 C 语言环境下对扩展字符进行分类,因为标准允许它们不必这样做。 (接下来是一个疯狂的猜测)完整的 Unicode 分类表很大,只需要 ASCII 的程序不必为它们的使用付费。

【讨论】:

我试图了解标准背后的原因。如果未指定,则区域设置为 "C"。因此,如果setlocale() 从 OP 中的示例中删除,它无论如何都必须工作,但它没有。是什么阻止 "C"i18n 继承,而 "en_US"i18n 继承? (见 IgnacioVazquez-Abrams 对 OP 的评论)

以上是关于为啥 wctype.h 中的函数在没有 setlocale() 的情况下不起作用?的主要内容,如果未能解决你的问题,请参考以下文章

error: No curses/termcap library found

为啥我的自定义函数调用方法中的 println 语句没有出现在日志中?

为啥在 TypeScript 中的“任何”字段类型变量上使用“字符串”函数时没有编译时错误?

Python 3-为啥我在这个作业问题中的 try 和 except 函数没有编译? [关闭]

为啥我的 DFS 函数中的“res”没有改变?

为啥 c++11 中的 lambda 函数没有 f​​unction<> 类型?