您的位置:首页 > 其它

setlocale()函数使用

2015-08-01 20:24 337 查看
转自:http://zyxhome.org/wp/cc-prog-lang/c-stdlib-setlocale-usage-note/

[在此向原文作者说声谢谢!若有读者看到文章转载时请写该转载地址,不要写我的BLOG地址。尊重他人的劳动成果^_^]

C和C++的标准库分别有自己的locale操作方法,C标准库的locale设定函数是setlocale(),而C++标准库有locale类和流对象的imbue()方法。这篇是我自己的setlocale()使用总结。


Linux的glibc中的setlocale()

具体参考:man3setlocale

头文件与声明如下:

1
#include
<locale.h>
2
char
*
setlocale
(
int
category,
const
char
*
locale);
说明:

category:为locale分类,表达一种locale的领域方面,通常有下面这些预定义常量:LC_ALL、LC_COLLATE、LC_CTYPE、LC_MESSAGES、LC_MONETARY、LC_NUMERIC、LC_TIME,其中LC_ALL表示所有其它locale分类的并集。

locale:为期望设定的locale名称字符串,在Linux/Unix环境下,通常以下面格式表示locale名称:language[_territory][.codeset][@modifier],language为ISO639中规定的语言代码,territory为ISO3166中规定的国家/地区代码,codeset为字符集名称。

在Linux下,可以使用locale-a命令查看系统中所有已配置的locale。用不带选项的locale命令查看当前Shell中活动的locale。用locale
-m命令查看locale系统支持的所有可用的字符集编码。
和locale相关的包叫做:locales,locale系统支持的所有可用locale在文件:/usr/share/i18n/SUPPORTED中列出。
在Debian下,可用dpkg-reconfigurelocales命令重新配置locale,也可以手工修改/etc/locale.gen文件,然后运行locale-gen命令。
在Ubuntu下,修改/var/lib/locales/supported.d/local文件,配置新的locale,然后运行locale-gen命令。

当locale为NULL时,函数只做取回当前locale操作,通过返回值传出,并不改变当前locale。

当locale为""时,根据环境的设置来设定locale,检测顺序是:环境变量LC_ALL,每个单独的locale分类LC_*,最后是LANG变量。为了使程序可以根据环境来改变活动locale,一般都在程序的初始化阶段加入下面代码:setlocale(LC_ALL,"")。

当C语言程序初始化时(刚进入到main()时),locale被初始化为默认的Clocale,其采用的字符编码是所有本地ANSI字符集编码的公共部分,是用来书写C语言源程序的最小字符集(所以才起locale名叫:C)。

当用setlocale()设置活动locale时,如果成功,会返回当前活动locale的全名称;如果失败,会返回NULL。


Windows的CRT中的setlocale()

具体参考:setlocale-MSDN
Run-TimeLibraryReference

在WindowsCRT的实现中还有一个使用wchar_t作为locale名的宽字符版本:_wsetlocale()。因此,也有了使用_TCHAR宏版本的setlocale():_tsetlocale()。

WindowsCRT实现的setlocale()和glibc版本的头文件与声明相同,使用方法类似,如下:

支持的locale分类常量:LC_ALL、LC_COLLATE、LC_CTYPE、LC_MONETARY、LC_NUMERIC、LC_TIME。

请求设定的locale名可以为以下格式(参考MSDN:Language
andCountry/RegionStrings):

lang[_country_region[.code_page]]:虽然形式与glibc的相同,当Windows的locale名并不符合POSIX的规范,比如采用GBK字符集的大陆中文,POSIX的名字为:zh_CN.GBK,而在
WindowsCRT中要用:Chinese_People'sRepublicofChina.936,(-_-^)。

lang字段的可用值参考:Lan
1b5d7
guage
Strings

country_region字段的可用值参考:Country/Region
Strings

code_page字段的可用值是Windows系统支持的代码页编号,参考:Code
PageIdentifiers

.code_page:可以直接使用代码页来设定locale,而且可以使用.OCP、.ACP两个伪代码页,.OCP表示从系统获得的当前活动的OEM代码页,.ACP表示从系统获得的活动ANSI代码页。

"":根据Windows系统环境的活动ANSI代码页来设定locale。.OCP、.ACP、和环境代码页都受控制面板中“区域与语言选项”的设置影响。默认装完简体中文版Windows后,活动的ANSI代码页为:936(即GBK),可用chcp控制台程序查看活动代码页。

NULL:取回当前locale,不改变当前locale。


setlocale()的作用和使用例子

当向终端、控制台输出wchar_t类型的字符时,需要设置setlocale(),因为通常终端、控制台环境自身是不支持UCS系列的字符集编码的,使用流操作函数时(如:printf()),在标准/RT库实现的内部会将UCS字符转换成合适的本地ANSI编码字符,转换的依据就是setlocale()设定的活动locale,最后将结果字符序列传递给终端,对于来自终端的输入流这个过程刚好相反。

可以用重定向输出流到文件的方法验证上面的机制:无论是WindowsCRT、Linuxglibc、Cygwinglibc,使用wprintf()打印wchar_t字符文本时,重定向到文件的内容总是GBK、UTF-8等本地ANSI编码,而不会是UCS编码。

下面是我写的一个使用setlocale()的示例:

01
#ifdef
__GNUC__
02
03
#define
CSET_GBK"GBK"
04
#define
CSET_UTF8"UTF-8"
05
06
#define
LC_NAME_zh_CN"zh_CN"
07
08
//
ifdef__GNUC__
09
#elif
defined(_MSC_VER)
10
11
#define
CSET_GBK"936"
12
#define
CSET_UTF8"65001"
13
14
#define
LC_NAME_zh_CN"Chinese_People'sRepublicofChina"
15
16
//
ifdef_MSC_VER
17
#endif
18
19
#define
LC_NAME_zh_CN_GBKLC_NAME_zh_CN"."CSET_GBK
20
#define
LC_NAME_zh_CN_UTF8LC_NAME_zh_CN"."CSET_UTF8
21
#define
LC_NAME_zh_CN_DEFAULTLC_NAME_zh_CN_GBK
22
23
void
print_current_loc();
24
25
int
main(
int
argc,
char
*
argv[])
26
{
27
char
*
locname=NULL;
28
const
wchar_t
*
strzh=L
"中文字符串"
;
29
30
print_current_loc();
31
32
//
使用指定的locale
33
locname
=
setlocale
(LC_ALL,
LC_NAME_zh_CN_DEFAULT);
34
if
(
NULL==locname)
35
{
36
printf
(
"setlocale()
with%sfailed.\n"
,
LC_NAME_zh_CN_DEFAULT);
37
}
38
else
39
{
40
printf
(
"setlocale()
with%ssucceed.\n"
,
LC_NAME_zh_CN_DEFAULT);
41
}
42
43
print_current_loc();
44
45
wprintf(L
"Zhong
textis:%ls\n"
,
strzh);
46
47
//
使用运行环境中的locale设置
48
locname
=
setlocale
(LC_ALL,
""
);
49
if
(
NULL==locname)
50
{
51
printf
(
"setlocale()
fromenvironmentfailed.\n"
);
52
}
53
else
54
{
55
printf
(
"setlocale()
fromenvironmentsucceed.\n"
);
56
}
57
58
print_current_loc();
59
60
wprintf(L
"Zhong
textis:%ls\n"
,
strzh);
61
62
puts
(
"End
ofprogram."
);
63
return
0;
64
}
65
66
//
打印当前locale
67
void
print_current_loc()
68
{
69
char
*
locname=
setlocale
(LC_ALL,
NULL);
70
printf
(
"Current
localeis:%s\n"
,
locname);
71
}
要使上面程序成功编译并执行,需要注意一下几点:

WindowsCRT是不支持UTF-8编码作为locale的,运行时使用setlocale(LC_ALL,".65001")会失败。

使用Linux和Cygwin的glibc时,要在终端显示正确的中文,需满足以下条件:

不要混用char和wchar_t版本的流操作函数,否则会导致这些函数运行异常,我用CygwinGCC4测试混用printf()和wprintf()时,程序甚至崩掉,所以要将上面程序中printf()语句全注释掉才行。WindowCRT的实现则没有这个问题。

运行环境的locale设置要和程序中setlocale()设定的locale一致,比如:终端的活动字符集、环境变量(一般用LANG),要设置为*.UTF-8,才能显示setlocale(LC_ALL,"zh_CN.UTF-8")设定的wchar_t的中文字符。

用GCC编译时,要使用UTF-8编码保存源文件,这是GCC在编译时,将wchar_t文字量(以L打头)正确转换为UCS编码保存在对象文件中的必需条件,用NativeANSI编码(比如:GBK)有wchar_t文字量的源文件时,GCC会编译出错,Linux和Cygwin的GCC都有这个约束。另外在LinuxGCC使用UCS-4编码保存
wchar_t,而Windows和CygwinGCC使用UCS-2。

用wprintf()时,要用%ls表示wchar_t的字符串,用%s表示char的字符串,具体参考:man
3wprintf,而Windows的实现用%ls、%s都可以正确输出wchar_t字符串。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: