C标准库的setlocale()⽤法笔记
[在此向原⽂作者说声谢谢!若有读者看到⽂章转载时请写该转载地址,不要写我的BLOG地址。尊重他⼈的劳动成果 ^_^ ]
C 和 C++ 的标准库分别有⾃⼰的 locale 操作⽅法,C 标准库的 locale 设定函数是 setlocale(),⽽ C++ 标准库有 locale 类和流对象的imbue() ⽅法。这篇是我⾃⼰的 setlocale() 使⽤总结。
Linux的glibc中的setlocale()
具体参考:
头⽂件与声明如下:
1#include <locale.h>
2char* setlocale(int category, const char* locale);
说明:
category:为locale分类,表达⼀种locale的领域⽅⾯,通常有下⾯这些预定义常量:LC_ALL、LC_COLL
ATE、LC_CTYPE、
LC_MESSAGES、LC_MONETARY、LC_NUMERIC、LC_TIME,其中 LC_ALL 表⽰所有其它locale分类的并集。
locale:为期望设定的locale名称字符串,在Linux/Unix环境下,通常以下⾯格式表⽰locale名称:language[_territory][.codeset]
[@modifier],language 为 ISO 639 中规定的语⾔代码,territory 为 ISO 3166 中规定的国家/地区代码,codeset 为字符集名称。
在Linux下,可以使⽤ locale -a 命令查看系统中所有已配置的 locale。⽤不带选项的 locale 命令查看当前 Shell 中活动的
locale。⽤ locale -m 命令查看locale系统⽀持的所有可⽤的字符集编码。
和locale相关的包叫做:locales,locale系统⽀持的所有可⽤locale在⽂件:/usr/share/i18n/SUPPORTED 中列出。
在Debian下,可⽤ dpkg-reconfigure locales 命令重新配置 locale,也可以⼿⼯修改 / ⽂件,然后运⾏ 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 被初始化为默认的 C locale,其采⽤的字符编码是所有本地 ANSI 字符集编码的公共部分,是⽤来书写C语⾔源程序的最⼩字符集(所以才起locale名叫:C)。
当⽤ setlocale() 设置活动 locale 时,如果成功,会返回当前活动 locale 的全名称;如果失败,会返回 NULL。
Windows的CRT中的setlocale()
具体参考:
在 Windows CRT 的实现中还有⼀个使⽤ wchar_t 作为 locale 名的宽字符版本:_wsetlocale()。因此,也有了使⽤ _TCHAR 宏版本的setlocale():_tsetlocale()。
Windows CRT 实现的 setlocale() 和 glibc 版本的头⽂件与声明相同,使⽤⽅法类似,如下:
⽀持的 locale 分类常量:LC_ALL、LC_COLLATE、LC_CTYPE、LC_MONETARY、LC_NUMERIC、LC_TIME。
请求设定的 locale 名可以为以下格式(参考MSDN:):
1. lang[_country_region[.code_page]]:虽然形式与 glibc 的相同,当 Windows 的 locale 名并不符合 POSIX 的规范,⽐如采⽤ GBK 字
符集的⼤陆中⽂,POSIX 的名字为:zh_CN.GBK,⽽在 Windows CRT 中要⽤:Chinese_People's Republic of China.936,(-_-^)。
lang 字段的可⽤值参考:
country_region 字段的可⽤值参考:
code_page 字段的可⽤值是 Windows 系统⽀持的代码页编号,参考:
2. .code_page:可以直接使⽤代码页来设定 locale,⽽且可以使⽤ .OCP、.ACP 两个伪代码页,.OCP 表⽰从系统获得的当前活动的
OEM 代码页,.ACP 表⽰从系统获得的活动 ANSI 代码页。
3. "":根据 Windows 系统环境的活动 ANSI 代码页来设定 locale。.OCP、.ACP、和环境代码页都受控制⾯板中“区域与语⾔选项”的设置
影响。默认装完简体中⽂版 Windows 后,活动的 ANSI 代码页为:936(即 GBK),可⽤ chcp 控制台程序查看活动代码页。
4. NULL:取回当前 locale,不改变当前 locale。
setlocale()的作⽤和使⽤例⼦
当向终端、控制台输出 wchar_t 类型的字符时,需要设置 setlocale(),因为通常终端、控制台环境⾃⾝是不⽀持 UCS 系列的字符集编码的,使⽤流操作函数时(如:printf()),在标准/RT库实现的内部会将 UCS 字符转换成合适的本地 ANSI 编码字符,转换的依据就是setlocale() 设定的活动 locale,最后将结果字符序列传递给终端,对于来⾃终端的输⼊流这个过程刚好相反。
可以⽤重定向输出流到⽂件的⽅法验证上⾯的机制:⽆论是 Windows CRT、Linux glibc、Cygwin glibc,使⽤ 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"
printf函数的作用是向终端13
14#define LC_NAME_zh_CN "Chinese_People's Republic of China"
15
16// ifdef _MSC_VER
17#endif
18
19#define LC_NAME_zh_CN_GBK LC_NAME_zh_CN "." CSET_GBK
20#define LC_NAME_zh_CN_UTF8 LC_NAME_zh_CN "." CSET_UTF8
21#define LC_NAME_zh_CN_DEFAULT LC_NAME_zh_CN_GBK
22
23void print_current_loc();
24
25int 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 %s failed.\n", LC_NAME_zh_CN_DEFAULT);
37 }
38 else
39 {
40 printf("setlocale() with %s succeed.\n", LC_NAME_zh_CN_DEFAULT);
41 }
42
43 print_current_loc();
44
45 wprintf(L"Zhong text is: %ls\n", strzh);
46
47 // 使⽤运⾏环境中的 locale 设置
48 locname = setlocale(LC_ALL, "");
49 if( NULL == locname )
50 {
51 printf("setlocale() from environment failed.\n");
52 }
53 else
54 {
55 printf("setlocale() from environment succeed.\n");
56 }
57
58 print_current_loc();
59
60 wprintf(L"Zhong text is: %ls\n", strzh);
61
62 puts("End of program.");
63 return0;
64}
65
66// 打印当前 locale
67void print_current_loc()
68{
69 char* locname = setlocale(LC_ALL, NULL);
70 printf("Current locale is: %s\n", locname);
71}
要使上⾯程序成功编译并执⾏,需要注意⼀下⼏点:
Windows CRT 是不⽀持 UTF-8 编码作为 locale 的,运⾏时使⽤ setlocale(LC_ALL, ".65001") 会失败。
使⽤ Linux 和 Cygwin 的 glibc 时,要在终端显⽰正确的中⽂,需满⾜以下条件:
1. 不要混⽤ char 和 wchar_t 版本的流操作函数,否则会导致这些函数运⾏异常,我⽤Cygwin GCC 4测试混⽤ printf() 和 wprintf() 时,程
序甚⾄崩掉,所以要将上⾯程序中 printf() 语句全注释掉才⾏。Window CRT 的实现则没有这个问题。
2. 运⾏环境的 locale 设置要和程序中 setlocale() 设定的 locale ⼀致,⽐如:终端的活动字符集、环境变量(⼀般⽤ LANG),要设置为
*.UTF-8,才能显⽰ setlocale(LC_ALL, "zh_CN.UTF-8") 设定的 wchar_t 的中⽂字符。
3. ⽤ GCC 编译时,要使⽤ UTF-8 编码保存源⽂件,这是 GCC 在编译时,将 wchar_t ⽂字量(以 L 打头)正确转换为 UCS 编码保存在
对象⽂件中的必需条件,⽤ Native ANSI 编码(⽐如:GBK)有 wchar_t ⽂字量的源⽂件时,GCC 会编译出错,Linux 和 Cygwin 的GCC 都有这个约束。另外在 Linux GCC 使⽤ UCS-4 编码保存 wchar_t,⽽ Windows 和 Cygwin GCC 使⽤ UCS-2。
4. ⽤ wprintf() 时,要⽤ %ls 表⽰ wchar_t 的字符串,⽤ %s 表⽰ char 的字符串,具体参考:,⽽ Windows 的实现⽤ %ls、%s 都可以正
确输出 wchar_t 字符串。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论