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()使用总结。
具体参考:man3setlocale
头文件与声明如下:
说明:
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。
具体参考: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。
当向终端、控制台输出wchar_t类型的字符时,需要设置setlocale(),因为通常终端、控制台环境自身是不支持UCS系列的字符集编码的,使用流操作函数时(如:printf()),在标准/RT库实现的内部会将UCS字符转换成合适的本地ANSI编码字符,转换的依据就是setlocale()设定的活动locale,最后将结果字符序列传递给终端,对于来自终端的输入流这个过程刚好相反。
可以用重定向输出流到文件的方法验证上面的机制:无论是WindowsCRT、Linuxglibc、Cygwinglibc,使用wprintf()打印wchar_t字符文本时,重定向到文件的内容总是GBK、UTF-8等本地ANSI编码,而不会是UCS编码。
下面是我写的一个使用setlocale()的示例:
要使上面程序成功编译并执行,需要注意一下几点:
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字符串。
[在此向原文作者说声谢谢!若有读者看到文章转载时请写该转载地址,不要写我的BLOG地址。尊重他人的劳动成果^_^]
C和C++的标准库分别有自己的locale操作方法,C标准库的locale设定函数是setlocale(),而C++标准库有locale类和流对象的imbue()方法。这篇是我自己的setlocale()使用总结。
Linux的glibc中的setlocale()
具体参考:头文件与声明如下:
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-MSDNRun-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 |
04 | #define |
05 |
06 | #define |
07 |
08 | // |
09 | #elif defined(_MSC_VER) |
10 |
11 | #define |
12 | #define |
13 |
14 | #define |
15 |
16 | // |
17 | #endif |
18 |
19 | #define |
20 | #define |
21 | #define |
22 |
23 | void print_current_loc(); |
24 |
25 | int main( int argc, char * argv[]) |
26 | { |
27 | char * |
28 | const wchar_t * "中文字符串" ; |
29 |
30 | print_current_loc(); |
31 |
32 | // |
33 | locname setlocale (LC_ALL, LC_NAME_zh_CN_DEFAULT); |
34 | if ( |
35 | { |
36 | printf ( "setlocale() , LC_NAME_zh_CN_DEFAULT); |
37 | } |
38 | else |
39 | { |
40 | printf ( "setlocale() , LC_NAME_zh_CN_DEFAULT); |
41 | } |
42 |
43 | print_current_loc(); |
44 |
45 | wprintf(L "Zhong , strzh); |
46 |
47 | // |
48 | locname setlocale (LC_ALL, "" ); |
49 | if ( |
50 | { |
51 | printf ( "setlocale() ); |
52 | } |
53 | else |
54 | { |
55 | printf ( "setlocale() ); |
56 | } |
57 |
58 | print_current_loc(); |
59 |
60 | wprintf(L "Zhong , strzh); |
61 |
62 | puts ( "End ); |
63 | return 0; |
64 | } |
65 |
66 | // |
67 | void print_current_loc() |
68 | { |
69 | char * setlocale (LC_ALL, NULL); |
70 | printf ( "Current , 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字符串。
相关文章推荐
- SVM(Support Vector Machine)
- UILabel
- DEX 方法超过64K限制和gradle编译OOM问题解决
- 【暑假集训】之被ACM金牌大神虐的第二天之图论篇
- 两个Integer值比较不相等问题
- leetCode 106.Construct Binary Tree from Inorder and Postorder Traversal (根据中序遍历和后序遍历构造二叉树)
- struts原理
- XJOI-NOIP2015提高组模拟题1 day1
- iOS开发-项目 知识分享与经验积累(一)
- Android 中保存数据到文件中
- acm-uva10653解题报告
- IOS中Json解析的四种方法
- cygwin不能执行make
- 设计模式之Factory----经典
- C语言:非减链表的合并
- leetCode 105.Construct Binary Tree from Preorder and Inorder Traversal (根据前序遍历和中序遍历构造二叉树)
- HDU 4366 Successor
- leetcode--Count Complete Tree Nodes
- T语言TC发布脚本方法
- java高级编程-使用反射强制给private字段赋值