转自: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()
具体参考:man 3 setlocale
头文件与声明如下:
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 为 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,也可以手工修改 /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 被初始化为默认的 C locale,其采用的字符编码是所有本地 ANSI 字符集编码的公共部分,是用来书写C语言源程序的最小字符集(所以才起locale名叫:C)。
当用 setlocale() 设置活动 locale 时,如果成功,会返回当前活动 locale 的全名称;如果失败,会返回 NULL。
Windows的CRT中的setlocale()
具体参考:setlocale - MSDN Run-Time Library Reference
在 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:Language and Country/Region Strings):
lang[_country_region[.code_page]]:虽然形式与 glibc 的相同,当 Windows 的 locale 名并不符合 POSIX 的规范,比如采用 GBK 字符集的大陆中文,POSIX 的名字为:zh_CN.GBK,而在 Windows CRT 中要用:Chinese_People's Republic of China.936,(-_-^)。
.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,最后将结果字符序列传递给终端,对于来自终端的输入流这个过程刚好相反。
可以用重定向输出流到文件的方法验证上面的机制:无论是 Windows CRT、Linux glibc、Cygwin glibc,使用 wprintf() 打印 wchar_t 字符文本时,重定向到文件的内容总是 GBK、UTF-8 等本地 ANSI 编码,而不会是 UCS 编码。
下面是我写的一个使用 setlocale() 的示例:
03 |
#define CSET_GBK "GBK" |
04 |
#define CSET_UTF8 "UTF-8" |
06 |
#define LC_NAME_zh_CN "zh_CN" |
09 |
#elif defined(_MSC_VER) |
11 |
#define CSET_GBK "936" |
12 |
#define CSET_UTF8 "65001" |
14 |
#define LC_NAME_zh_CN "Chinese_People's Republic of China" |
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 |
23 |
void print_current_loc(); |
25 |
int main(int argc, char* argv[]) |
28 |
const wchar_t* strzh = L"中文字符串"; |
33 |
locname = setlocale(LC_ALL, LC_NAME_zh_CN_DEFAULT); |
34 |
if ( NULL == locname ) |
36 |
printf("setlocale() with %s failed.\n", LC_NAME_zh_CN_DEFAULT); |
40 |
printf("setlocale() with %s succeed.\n", LC_NAME_zh_CN_DEFAULT); |
45 |
wprintf(L"Zhong text is: %ls\n", strzh); |
48 |
locname = setlocale(LC_ALL, ""); |
49 |
if ( NULL == locname ) |
51 |
printf("setlocale() from environment failed.\n"); |
55 |
printf("setlocale() from environment succeed.\n"); |
60 |
wprintf(L"Zhong text is: %ls\n", strzh); |
62 |
puts("End of program."); |
67 |
void print_current_loc() |
69 |
char* locname = setlocale(LC_ALL, NULL); |
70 |
printf("Current locale is: %s\n", locname); |
要使上面程序成功编译并执行,需要注意一下几点:
Windows CRT 是不支持 UTF-8 编码作为 locale 的,运行时使用 setlocale(LC_ALL, ".65001") 会失败。
使用 Linux 和 Cygwin 的 glibc 时,要在终端显示正确的中文,需满足以下条件:
不要混用 char 和 wchar_t 版本的流操作函数,否则会导致这些函数运行异常,我用Cygwin GCC 4测试混用 printf() 和 wprintf() 时,程序甚至崩掉,所以要将上面程序中 printf() 语句全注释掉才行。Window CRT 的实现则没有这个问题。
运行环境的 locale 设置要和程序中 setlocale() 设定的 locale 一致,比如:终端的活动字符集、环境变量(一般用 LANG),要设置为 *.UTF-8,才能显示 setlocale(LC_ALL, "zh_CN.UTF-8") 设定的 wchar_t 的中文字符。
用 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。
用 wprintf() 时,要用 %ls 表示 wchar_t 的字符串,用 %s 表示 char 的字符串,具体参考:man 3 wprintf,而 Windows 的实现用 %ls、%s 都可以正确输出 wchar_t 字符串。
http://www.cnblogs.com/hnrainll/archive/2011/05/07/2039700.html
- Java的类锁、对象锁和方法锁
在Java中,对于synchronized关键字,大家看到的第一反应就是这个关键字是进行同步操作的,即得名"同步锁". 当用它来修饰方法和代码块时,默认当前的对象为锁的对象,即对象 ...
- synchronized类锁,对象锁,方法锁
synchronized从语法的维度一共有3个用法: 静态方法加上关键字 实例方法(也就是普通方法)加上关键字 方法中使用同步代码块 前两种方式最为偷懒,第三种方式比前两种性能要好. synchron ...
- 控制台程序的中文输出乱码问题(export LC_CTYPE=zh_CN.GBK,或者修改/etc/sysconfig/i18n为zh_CN.GBK。使用setlocale(LC_CTYPE, "");会使用默认办法。编译器会将源码做转换成Unicode格式,或者指定gcc的输入文件的编码参数-finput-charset=GBK。Linux下应该用wprintf(L"%ls/n",wstr))
今天发现用securecrt登陆时,gcc编译出错时会出现乱码,但直接在主机的窗口界面下用Shell编译却没有乱码.查看了一下当时的错误描述,发现它的引号是中文引号,导致在SecureCRT中显示出错 ...
- ca75a_c++_标准IO库-利用流对象把文件内容读取到向量-操作文件
/*ca75a_c++_标准IO库习题练习习题8.3,8.4,8.6习题8.9.8.10 ifstream inFile(fileName.c_str());1>d:\users\txwtech ...
- [Effective JavaScript 笔记]第28条:不要信赖函数对象的toString方法
js函数有一个非凡的特性,即将其源代码重现为字符串的能力. (function(x){ return x+1 }).toString();//"function (x){ return x+ ...
- JavaScript 中的常用12种循环遍历(数组或对象)的方法
1.for 循环 let arr = [1,2,3]; for (let i=0; i<arr.length; i++){ console.log(i,arr[i]) } // 0 1 // 1 ...
- 关于 XMLHttpRequest对象的onreadyStateChange方法
最近做了一个Ajax的demo,前台用HTML+javascript,后台用一个servlet来响应,流程如下: 页面点击链接事件,由js捕获,生成一个请求到后台,servlet处理后给出响应信息,并 ...
- Linux下c函数dlopen实现加载动态库so文件代码举例
dlopen()是一个强大的库函数.该函数将打开一个新库,并把它装入内存.该函数主要用来加载库中的符号,这些符号在编译的时候是不知道的.这种机制使得在系统中添加或者删除一个模块时,都不需要重新编译了. ...
- java类的结构(属性、方法、构造函数)
一.类的定义形式类定义的一般形式如下 [类定义修饰符] class <类名> { //类体 [成员变量声明] [构造函数] [成员方法] } 前面说过,在描述java语法时,方括号中 ...
随机推荐
- React Native : 自定义视图
代码地址如下:http://www.demodashi.com/demo/11686.html 这次我们要做的仿 新闻头条 的首页的顶部标签列表,不要在意新闻内容. 请求数据 首先做顶部的目录视图,首 ...
- Python 的基本运算和内置函数
一.运算符 (一)Python算术运算符 以下假设变量: a=10,b=20: 运算符 描述 实例 + 加 - 两个对象相加 a + b 输出结果 30 - 减 - 得到负数或是一个数减去另一个数 a ...
- win10下iis绑定局域网ip无效的解决方案
win7不会出现此问题 win10会 win8未测试 问题描述 <binding protocol="http" bindingInformation="*:808 ...
- RHEL 5.4下部署LVS(DR)+keepalived实现高性能高可用负载均衡(转)
一.简介 LVS是Linux Virtual Server的简写,意即Linux虚拟服务器,是一个虚拟的服务器集群系统.本项目在1998年5月由章文嵩博士成立,是中国国内最早出现的自由软件项目之一. ...
- Linux下查看分区UUID
有两种方法: 1.#:blkid 2.ls -l /dev/disk/by-uuid/
- Silverlight-管理独立存储(Isolated Storage)
Silverlight中的独立存储是其内部的可信任的可访问文件空间,在这里你可以使用Silverlight 随意的创建.读取.写入.删除目录和文件,它有一些类似于Cookie,但是它可以在客户端保存大 ...
- TCP/IP笔记(一)网络基础知识
计算机与网络发展 计算机自诞生伊始,经历了一系列演变与发展.大型通用机计算机.超级计算机.小型机.个人电脑.工作站.便携式电以及现如今的智能手机终端都是这一过程的产物.它们性能逐年增强,价格却逐年下降 ...
- 深入理解:单一入口、MVC、ORM、CURD、ActiveRecord概念
本篇文章是对单一入口.MVC.ORM.CURD.ActiveRecord概念进行了详细的分析介绍,需要的朋友参考下 MVC MVC是一个设计模式,它强制性的使应用程序的输入.处理和输出分开.使 ...
- Hibernate体系结构
Hibernate架构包括许多对象持久对象,会话工厂,事务工厂,连接工厂,会话,事务等. hibernate架构中有4层Java应用层,hibernate框架层,反手api层和数据库层.请参见hibe ...
- Java 学习笔记及资源
Spring框架入门HelloWorld :http://www.importnew.com/13246.html (iteye 唐 博客,跟我学Sprint) Spring 框架下载地址:http ...