上文中提到了C++中的宽字符和窄字符,本文将继续探讨其在国际化代码中的影响。老规矩,先看问题!本文援引一个安装时路径含有非英文字符,随后写入注册表键值,导致后续集成工作无法进行的真实案例。
而这个path值则来源于以下的结构。
typedef struct _AgentRegEntry {
HANDLE hive;
char *rpcCommand;
char *productName;
char *keyPath;
char *valueName;
unsigned int type;
} AgentRegEntry;
看到这里,其实我们已经清楚了该问题的根源所在,用char来定义keyPath。这对国际化测试人员来说,应该算是个不大不小的利好吧,无需继续执行相关测试用例,直接报i18n bug即可!
为什么这么说呢?因为作为窄字符的char是用8bit表示的定长byte,char字符只能表示ASII码表中的256个字符,包括前128个可见字符和后面的128个不可见字符。所以类似于中文路径这样用例他是完全无法处理的。
面对这样的国际化问题,又应该如何解决呢?我这里有两个锦囊,第一个是泰版的,也叫“糙”版;第二个是欧版的,也叫“国际化粉”版。
1、 泰版
具体说来倒也简单,直接在release note中声明不支持非英文路径即可啊!很难相信有客户要求必须支持中文或日文安装路径,否则就不买你的产品吧。这时有人窃窃私语,这也忒糙了吧?……嗯,我承认这个锦囊整体做工上是糙了点儿,但胜在够快够猛啊!
2、 欧版
首先引入新的类型——wchar_t!
因为char所能表示的字符数太少,于是乎wchar_t应运而生,它可以占8bit,16bit或32bit。长度根据指定平台上想要用的encoding编码方式来设定的。
在WIN32 MSVC环境下,wchar_t按照utf-16编码。但因为wchar_t定义的长度只有2个字节,所以它不能表示utf-16编码长度为4字节的字符。即wchar_t只能表示utf-16字符集中的一个子集。
在Linux的环境下,wchar_t的长度则为四字节,按照utf-32编码。
哦~~~原来是换个类型就可以搞定的事儿啊,pretty easy啊!立刻动手试试吧。
wchar_t lwide = L'宽';
wchar_t wide = '宽';
wcout.imbue(locale("chs"));
printf("%0x %0x ", lwide, wide);
wcout << lwide << endl;
wcout << wide << endl;
console输出结果是这样的。
5bbd bfed
宽
咦!是不是少了点儿什么,wide什么都没打出来啊!
观察示意代码,虽然都使用了wchar_t,赋值也都一样,唯一的不同就是多了一个L。这个L什么意思呢?其实L代表每个字符都要用多字节表示。也就是说,wchar_t不光是可以存储unicode宽字符,也可以存储其它的编码。例如ANSI。基于此,我们可以总结如下。
wchar_t是一个可以表示字符集中的任意一个字符的足够宽的变量类型。wchar_t编码方式也是可以改变或者说与平台相关的,如ANSI,UTF-16或UTF-32。我们不能假定wchar_t已有的编码方式,甚至根据编码方式做相关的截取操作等,只能将其视为足够宽的字符类型。