哪些组件使用区域设置变量?

时间:2018-05-30 14:00:48

标签: c linux environment-variables

我已经读过每个进程都有一组与之关联的语言环境变量。例如,这些是与我的系统上的bash进程关联的语言环境变量:

$ locale
LANG="en_GB.UTF-8"
LC_COLLATE="en_GB.UTF-8"
LC_CTYPE="en_GB.UTF-8"
LC_MESSAGES="en_GB.UTF-8"
LC_MONETARY="en_GB.UTF-8"
LC_NUMERIC="en_GB.UTF-8"
LC_TIME="en_GB.UTF-8"
LC_ALL=

我想知道谁实际使用这些语言环境变量。

C标准函数(例如:fwrite())和Linux系统调用是否使用它们?某些C标准函数或某些Linux系统调用的行为是否因某些语言环境变量的值而异?

或者只是某些程序可以使用这些语言环境变量?例如,我可以编写一个程序,根据LANG语言环境变量的值,以不同的语言向用户显示消息。

3 个答案:

答案 0 :(得分:11)

By default, C's standard library functions use the "C" locale。您可以将其切换到用户区域设置以启用特定于语言环境的内容:

  • 字符处理
  • 整理
  • 日期/时间格式
  • 数字编辑
  • 货币格式
  • 信息

POSIX setlocale文档包含受其影响的区域设置相关函数的不完整列表:

  

catopen,exec,fprintf,fscanf,isalnum,isalpha,isblank,iscntrl,isdigit,isgraph,islower,isprint,ispunct,isspace,isupper,iswalnum,iswalpha,iswblank,iswcntrl,iswctype,iswdigit,iswgraph,iswlower,iswprint ,iswpunct,iswspace,iswupper,iswxdigit,isxdigit,localeconv,mblen,mbstowcs,mbtowc,newlocale,nl_langinfo,perror,psiginfo,setlocale,strcoll,strerror,strfmon,strftime,strsignal,strtod,strxfrm,tolower,toupper,towlower,towupper ,uselocale,wcscoll,wcstod,wcstombs,wcsxfrm,wctomb

E.g:

printf("%'d\n", 1000000000);
printf("Setting LC_ALL to %s\n", getenv("LANG"));
setlocale(LC_ALL, ""); // Set user-preferred locale.
printf("%'d\n", 1000000000);

输出:

1000000000
Setting LC_ALL to en_US.UTF-8
1,000,000,000

答案 1 :(得分:4)

  

我已经读过每个进程都有一组与之关联的语言环境变量。

这不是真的,或者至少它过于简单。

许多标准库函数(和非标准库函数)基于一组区域设置配置修改其行为,这些配置在标准库实现中的某个隐藏全局对象中维护。 (在某些库实现中,使用线程局部静态变量来维护每个线程而不是全局的区域设置配置。)这似乎与进程相关联,因为通常每个进程都有一个标准库的实例&#39 ; s运行时,但重要的是要理解 - 尽管有外观 - 语言环境支持是库的一部分,而不是操作系统内核。 (当然,任何标准中都没有定义内核的边界,甚至内核可能是什么。你可以运行你的程序"裸机"或者你可能有一个考虑它的操作系统在系统调用中实现标准库很有用。我在这里谈论常见的情况。)

基本语言环境配置由第7.11节(C11标准)中的C标准定义,该标准定义了两个接口:

  • setlocale,修改了库的语言环境配置,

  • localeconv,用于查询部分语言环境配置,允许用户代码符合语言环境的数字格式约定(包括货币格式)。

区域设置配置分为多个或多或少的独立组件,称为"类别"。 (C ++标准库称这些" facets",这也是一个常用词。)C标准定义了五个类别,Posix定义了一个类别,但类别是开放式的;各个标准库实现可以自由添加其他类别。例如,大多数Linux系统上使用的Gnu标准C库目前共有12个类别。 (有关当前列表,请参阅系统上的man 7 locale。)

标准类别是:

  • LC_CTYPE:字符分类和大小写转换。
  • LC_COLLATE:整理顺序。
  • LC_MONETARY:货币格式。
  • LC_NUMERIC:数字,非货币格式。
  • LC_TIME:日期和时间格式。

和Posix扩展名为:

  • LC_MESSAGES:信息和诊断信息以及互动响应的格式。

localeconv之外,LC_NUMERIC仅提供对LC_MONETARYsetlocale类别中特定配置的访问权限,因此无法查询任何特定配置。

此外,没有标准的方法来设置单个配置。您所能做的就是使用C来配置整个类别,使用依赖于库和非标准化的区域设置名称(这只是一个字符串)。更确切地说,两个区域设置名称是标准化的:

  • C标准定义了区域设置名称POSIX

  • Posix定义区域设置名称C。但是,Posix指定相应的语言环境应与名为locale的语言环境相同。

有关您正在使用的环境的setlocale文档中详细介绍了区域设置命名的详细信息,但通常情况下,区域设置感知程序永远不会调用setlocale使用除标准名称之外的字符串常量或空字符串。 (我将在一分钟内完成。)

<locale.h>接口允许程序设置单个区域设置类别,或将所有区域设置类别设置为相同的区域设置名称。它还返回一个字符串,该字符串可用于返回先前配置的区域设置类别(或完整配置)。

上面类别列表中显示的类别名称是LC_ALL中定义的宏。另一个宏LC_ALL也由该头文件定义:setlocale。其中一个宏必须用作C的第一个参数。

C和Posix标准都要求程序启动时的初始语言环境设置是C语言环境。 Posix语言环境的许多方面都是标准化的(setlocale语言环境的某些方面是标准化的)。例如,这种标准化允许程序员预测数字转换的工作方式。

但通常情况是程序员希望与该用户自己的区域设置首选项进行交互。显然不希望每个程序都有自己的特殊机制来确定用户的区域设置偏好是什么,因此标准库提供了一种机制,用于将区域设置(或单个区域设置类别)设置为默认区域设置。配置为:使用空字符串("")作为区域设置名称调用setlocale。 C标准没有规定配置此信息的任何特定机制;它只是假设一个存在。

(旁注:使用空字符串调用setlocale作为区域设置名称​​不与使用NULL作为区域设置名称调用NULL相同。{{ 1}}告诉setlocale不要更改任何语言环境设置,但它仍会返回与当前语言环境关联的字符串。这样就不需要getlocale接口了。)

Posix确实指定了一种配置用户首选项的机制,它还坚持(大多数)标准化命令行实用程序在默认语言环境中运行。该机制使用其名称对应于setlocale类别宏的环境变量。

在Posix实现上,当程序调用{​​{1}}时,库将继续检查当前环境:

  1. 首先,它查找环境变量setlocale(LC_X, "");。如果已定义并且具有非空值,则用于定义区域设置。

  2. 否则,如果LC_ALL的第一个参数不是setlocale,它会查找其名称与该参数相同的环境变量。如果已定义并且具有非空值,则用于定义区域设置。

  3. 否则,如果定义了环境变量LC_ALL并且具有非空值,则使用它(以某种实现依赖方式)来构造区域设置名称。 (LANG应该表示用户的语言,这是他们语言环境偏好的重要组成部分。)

  4. 最后,使用了一些系统范围的默认值。

  5. 环境变量通常由LANG程序(或等效的GUI)根据系统配置文件初始化。 (精确的机制因分布而异,通常很难找到文档。)

    如上所述,Posix几乎需要所有标准shell实用程序来执行相当于login的操作,以便在用户配置的语言环境中运行。每个实用程序的联机帮助页(或其他文档)都应该指明它是否这样做,但除非有相反的信息,否则合理地假定它确实存在。

    此外,许多(但不是全部)标准库字符串函数都是区域设置感知的。绝对不能识别区域设置的库接口包括setlocale(LC_ALL, "");isdigit,它们始终基于isxdigit区域设置进行响应,而C则比较相同的字符串方式为strcmp,使用memcmp值(解释为char)来确定整理顺序。 (unsigned int是区域设置感知的,如果你想根据strcoll进行比较。)用于宽字符和多字节字符的字符编码由{{1}控制(以某种未指定的方式) } category。

答案 2 :(得分:4)

许多程序设置区域设置,并至少将其用于国际化。一些具体的例子:

LANG="en_GB.UTF-8"

这是您没有专门设置为其他类别的任何类别的区域设置。它允许系统以向后兼容的方式添加新的语言环境变量。

LC_COLLATE="en_GB.UTF-8"

这将选择在字符串上使用哪种语言的排序顺序。例如, Ch 被认为是西班牙语中的一个字母,将在 Cz 之后出现。使用它的一个C库函数是strcoll(),POSIX命令包括ls(按名称排序文件时)和sort

LC_CTYPE="en_GB.UTF-8"

这决定了当前的字符编码。在C11中,您可以设置此项,然后使用宽字符输入和输出,例如wprintf()。该库将透明地转换宽字符和外部世界使用的字符集。这仍然不适用于Windows,除非你做一些额外的魔术,但在其他地方,UTF-8已成为标准。越来越多的程序,如clang(从版本7开始),不再支持UTF-8以外的任何程序。

LC_MESSAGES="en_GB.UTF-8"

这确定了您在本地消息中看到的语言和字符集。在Unix / Linux上的C语言中,这些通常由.po库从gettext文件加载。

LC_MONETARY="en_GB.UTF-8"

这会影响strfmon()格式化货币数量的方式。

LC_NUMERIC="en_GB.UTF-8"

这决定了formatting of numbers不是金额。

LC_TIME="en_GB.UTF-8"

这会影响时间格式。在shell中尝试LC_TIME=fr_FR.UTF-8 date查看示例。 (或者使用locale -a | grep UTF选择一些适合异国情调的语言环境。)另外,还要检查您的时区和ntpd是否正常运行。

LC_ALL=

使用LANG代替此。它一次设置每个语言环境类别,但它会覆盖所有其他语言环境变量中的值。它的存在是为了向后兼容。

例如,我在Linux机器上使用LANG=en_US.utf8,但我覆盖LC_TIME=en_GB.utf8以获得24小时英语时间。如果设置LC_ALL,则无法执行此操作。

LANG还允许您将默认设置转换为系统支持的任何其他语言环境信息,例如LC_ADDRESSLC_IDENTIFICATIONLC_RESPONSELC_MEASUREMENTLC_TELEPHONE