<locale.h> 在 C 语言里负责“区域环境”这件事:程序可以据此决定数字的小数点写法、千位分隔符、货币符号,甚至字符串比较和时间显示规则。对需要做国际化输出、或者在不同系统区域设置下运行的程序来说,理解这个头文件的行为,能帮助你判断什么时候该切换区域,什么时候该读取当前格式信息。
下面按两个最常用的入口来梳理:先看如何用 setlocale 查询和设置区域环境,再看 localeconv 能拿到哪些格式化细节,最后用一个货币输出示例把它们串起来。
什么是 <locale.h>,它解决什么问题
locale.h 属于 C 语言标准库,主要用于处理本地化信息。所谓本地化,就是根据特定地区或语言调整程序行为与显示格式,例如:
- 日期和时间的表示方式
- 数字的小数点和千位分隔符
- 货币符号与金额排列方式
- 字符分类、转换和字符串比较规则
这类能力通常不是业务逻辑本身的一部分,但一旦程序面向不同地区用户,它就会直接影响输出结果是否符合当地习惯。
用 setlocale 设置或查询区域环境
函数原型与返回值
setlocale 用来设置或者查询当前程序的区域环境,原型如下:

#include <locale.h> char *setlocale(int category, const char *locale);
它的两个参数各自承担不同职责:
category:指定要修改或查询的区域类别。locale:指定目标区域名称;传入NULL时表示只查询当前设置。
如果 locale 为 NULL,函数会返回当前区域名称;如果传入的是有效区域名称,函数会尝试切换到新区域,并返回指向新区域名称的字符串。
常见 LC_* 分类有哪些
category 参数可使用以下常见取值:
LC_ALL:所有区域类别的集合。LC_COLLATE:字符串比较规则。LC_CTYPE:字符分类和转换。LC_MONETARY:货币格式。LC_NUMERIC:数字格式。LC_TIME:时间格式。
实际使用时,LC_ALL 适合一次性整体切换;如果你只想影响数字或货币输出,也可以只设置对应类别,减少对其他行为的影响。
查询并切换区域的示例
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <locale.h>
int main() {
// 查询当前区域环境
printf("Current locale: %sn", setlocale(LC_ALL, NULL));
// 设置区域环境为美国英语
setlocale(LC_ALL, "en_US.UTF-8");
// 再次查询区域环境
printf("New locale after setting: %sn", setlocale(LC_ALL, NULL));
return 0;
}这段代码先通过 setlocale(LC_ALL, NULL) 查询当前区域,再尝试切换到 "en_US.UTF-8",最后再次读取结果。它适合用来验证某个区域名称在当前系统上是否可用,以及切换是否真正生效。
用 localeconv 读取数字和货币格式
函数原型
如果程序已经设置好区域环境,接下来就可以通过 localeconv 读取当前环境下的数值与货币格式信息:

#include <locale.h> struct lconv *localeconv(void);
这个函数返回一个指向 struct lconv 的指针,结构体里保存了本地化格式所需的各项细节。
`struct lconv` 里包含哪些字段
原文给出的结构体定义如下:
// www.ja vascriptcn.com code example
struct lconv {
char *decimal_point; // 小数点字符
char *thousands_sep; // 千位分隔符字符
char *grouping; // 分组规则
char *int_curr_symbol; // 国际货币符号
char *currency_symbol; // 货币符号
char *mon_decimal_point; // 货币小数点字符
char *mon_thousands_sep; // 货币千位分隔符字符
char *mon_grouping; // 货币分组规则
char *positive_sign; // 正数符号
char *negative_sign; // 负数符号
char int_frac_digits; // 国际小数位数
char frac_digits; // 小数位数
char p_cs_precedes; // 正数货币符号位置
char p_sep_by_space; // 正数货币符号与数值之间是否使用空格
char n_cs_precedes; // 负数货币符号位置
char n_sep_by_space; // 负数货币符号与数值之间是否使用空格
char p_sign_posn; // 正数符号位置
char n_sign_posn; // 负数符号位置
};其中最常见、也最容易直接用到的字段包括:
decimal_point:普通数字使用什么小数点字符。thousands_sep:普通数字使用什么千位分隔符。currency_symbol:当前区域的货币符号。frac_digits:货币通常保留几位小数。
如果你的程序需要自己拼接格式化输出,而不是完全依赖库函数,这些字段就是最直接的数据来源。
读取当前区域格式信息的示例
// www.ja vascriptcn.com code example
#include <stdio.h>
#include <locale.h>
int main() {
// 设置区域环境
setlocale(LC_ALL, "zh_CN.UTF-8");
struct lconv *lc = localeconv();
printf("Decimal point: %sn", lc->decimal_point);
printf("Thousand separator: %sn", lc->thousands_sep);
return 0;
}这个示例先把区域设置为 "zh_CN.UTF-8",再读取当前环境中的小数点和千位分隔符。它说明了一点:localeconv 本身不负责“切换”,它只负责“读取当前设置下的格式信息”。
如何结合 localeconv 格式化货币输出
下面这段示例展示了如何基于当前区域环境中的货币规则进行输出:

// www.ja vascriptcn.com code example
#include <stdio.h>
#include <locale.h>
#include <wchar.h>
#include <wctype.h>
int main() {
// 设置区域环境
setlocale(LC_ALL, "zh_CN.UTF-8");
struct lconv *lc = localeconv();
wchar_t currency[32];
swprintf(currency, sizeof(currency)/sizeof(wchar_t), L"%.*f %s",
lc->frac_digits, 1234567.89, lc->currency_symbol);
wprintf(L"Formatted currency: %lsn", currency);
return 0;
}这段代码的处理顺序比较清楚:
- 先调用
setlocale(LC_ALL, "zh_CN.UTF-8")设置区域环境。 - 再通过
localeconv()读取当前货币相关字段。 - 使用
lc->frac_digits控制小数位数。 - 把
lc->currency_symbol拼接到最终输出中。
原文使用了宽字符相关函数 swprintf 与 wprintf。这类写法适合需要处理本地化字符输出的场景,尤其是在货币符号或字符集不止 ASCII 的情况下。
实际使用时应注意什么
从这几个示例可以看出,<locale.h> 的核心思路并不复杂:先确定程序当前使用哪个区域,再根据这个区域去读取数字、货币或时间等规则。真正需要注意的是,区域名称是否在目标系统上可用,以及你设置的是整体区域还是某个具体分类。
如果只是想读取当前环境,直接用 setlocale(LC_ALL, NULL);如果要根据地区输出格式化内容,则通常要先调用 setlocale,再调用 localeconv 之类的接口获取细节。
总结
对于需要国际化输出的 C 程序,<locale.h> 是绕不开的一部分。setlocale 负责查询和切换区域环境,localeconv 负责提供数字和货币格式细节;把这两个接口配合起来,就能让程序更贴近不同地区的显示习惯。









