如果没有setlocale(),为什么wctype.h中的函数不起作用?

时间:2016-11-09 04:58:50

标签: c glibc wchar-t setlocale widechar

我的设置: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的函数可以使用具有固定编码的宽字符。 (不言而喻,如果我们希望setlocale()中的函数与非ASCII字符一起正常工作,并且我们使用wchar.h中的字符转换函数来设置外部编码,则需要ctype.h。)

为什么示例在没有setlocale()的情况下无效?

1 个答案:

答案 0 :(得分:1)

C标准说:

  

7.25宽字符分类和映射实用程序<wctype.h>

     

...

     

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

此外(5.2.1字符集)

  

应定义两组字符及其关联的整理顺序:设置   写入哪些源文件(源字符集),以及在中解释的集合   执行环境(执行字符集)。每组进一步分为a   基本字符集,其内容由本子条款给出,以及一组零或更多   调用区域设置特定成员(不是基本字符集的成员)   扩展字符。

然后(7.19通用定义<stddef.h>

  

wchar_t   这是一个整数类型,其值范围可以表示支持的语言环境中指定的最大扩展字符集的所有成员的不同代码

因此可能有许多扩展字符集,每个区域设置一个。因此,wchar_t编码可能与语言环境有关,因为编码是一组整数代码和一组字符之间的映射,后者可能与语言环境有关。

鉴于上述情况,<wctype.h> 必须依赖于语言环境。否则,标准必须强制要求存在单个与语言环境无关的扩展字符集。

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

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