随笔 - 96  文章 - 255  trackbacks - 0
<2010年6月>
303112345
6789101112
13141516171819
20212223242526
27282930123
45678910

E-mail:zbln426@163.com QQ:85132383 长期寻找对战略游戏感兴趣的合作伙伴。

常用链接

留言簿(21)

随笔分类

随笔档案

SDL相关网站

我的个人网页

我的小游戏

资源下载

搜索

  •  

积分与排名

  • 积分 - 485062
  • 排名 - 37

最新评论

阅读排行榜

评论排行榜

<本文PDF文档下载>

std::locale

通过前面两节的知识,我们知道了在C/C++中,字符(串)和宽字符(串)之间的转换不是简单的,固定的数学关系,宽窄转换依赖于本地化策略集(locale)。换句话说,一个程序在运行之前并不知道系统的本地化策略集是什么,程序只有在运行之后才通过locale获得当时的本地化策略集。
C有自己的locale函数,我们这里直接介绍C++的locale类。
先讨论locale的构造函数:
locale() throw();
这个构造函数是获得当前程序的locale,用法如下:
std::locale app_loc = std::locale();
或者(这是构造对象的两种表示方式,后同)
std::locale app_loc;
另外一个构造函数是:
explicit locale(const char* name);
这个构造函数以name的名字创建新的locale。重要的locale对象有:
std::locale sys_loc("");      //获得当前系统环境的locale
std::locale C_loc("C");      或者      std::locale C_loc = std::locale::classic();      //获得C定义locale
std::locale old_loc = std::locale::global(new_loc);      //将new_loc设置为当前全局locale,并将原来的locale返回给old_loc
除了这些,其它的name具体名字依赖于C++编译器和操作系统,比如Linux下gcc中文系统的locale名字为"zh_CN.UTF-8",中文Windows可以用"chs"(更加完整的名字可以用name()函数查看)。

mbstowcs()和wcstombs()

这两个C运行时库函数依赖于全局locale进行转换,所以,使用前必须先设置全局locale。
std::locale已经包含在<iostream>中了,再加上我们需要用到的C++字符串,所以包含<string>。
我们先看窄到宽的转换函数:
const std::wstring s2ws(const std::string& s)
{
    std::locale old_loc 
=
        std::locale::global(std::locale(
""));

    
const char* src_str = s.c_str();
    
const size_t buffer_size = s.size() + 1;
    wchar_t
* dst_wstr = new wchar_t[buffer_size];
    wmemset(dst_wstr, 
0, buffer_size);
    mbstowcs(dst_wstr, src_str, buffer_size);
    std::wstring result 
= dst_wstr;
    delete []dst_wstr;

    std::locale::global(old_loc);

    
return result;
}
我们将全局locale设置为系统locale,并保存原来的全局locale在old_loc中。
在制定转换空间缓存大小的时候,考虑如下:char是用1个或多个对象,也就是1个或者多个字节来表示各种符号:比如,GB2312用1个字节表示数字和字母,2个字节表示汉字;UTF-8用一个字节表示数字和字母,3个字节表示汉字,4个字节表示一些很少用到的符号,比如音乐中G大调符号等。wchar_t是用1个对象(2字节或者4字节)来表示各种符号。因此,表示同样的字符串,宽字符串的大小(也就是wchar_t对象的数量)总是小于或者等于窄字符串大小(char对象数量)的。+1是为了在最后预留一个值为0的对象,以便让C风格的char或者wchar_t字符串自动截断——这当然是宽串大小等于窄串大小的时候才会用上的,大部分时候,字符串早在前面某个转换完毕的位置就被0值对象所截断了。
最后我们将全局locale设置回原来的old_loc。
窄串到宽串的转换函数:
const std::string ws2s(const std::wstring& ws)
{
    std::locale old_loc 
=
        std::locale::global(std::locale(
""));

    
const wchar_t* src_wstr = ws.c_str();
    size_t buffer_size 
= ws.size() * 4 + 1;
    
char* dst_str = new char[buffer_size];
    memset(dst_str, 
0, buffer_size);
    wcstombs(dst_str ,src_wstr, buffer_size);
    std::
string result = dst_str;
    delete []dst_str;

    std::locale::global(old_loc);

    
return result;
}
这里考虑转换空间缓存大小的策略正好相反,在最极端的情况下,所有的wchar_t都需要4个char来表示,所以最大的可能就是4倍加1。
这两个函数在VC和gcc中都能正常运行(MinGW因为前面说到的原因不支持宽字符的正常使用),在VC中会给出不安全的警告,这是告诉给那些弄不清宽窄转换实质的人的警告,对于了解到目前这些知识的你我来说,这就是啰嗦了。
posted on 2010-06-26 11:17 lf426 阅读(2913) 评论(1)  编辑 收藏 引用 所属分类: 语言基础、数据结构与算法

FeedBack:
# re: 彻底解密C++宽字符:3、利用C运行时库函数转换 2010-06-26 20:38 Sunshine Alike
这个好,我先学习了~  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理